En la programación orientada a objetos , una metaclase es una clase cuyas instancias son clases. Así como una clase ordinaria define el comportamiento de ciertos objetos, una metaclase define el comportamiento de ciertas clases y sus instancias. No todos los lenguajes de programación orientados a objetos admiten metaclases. Entre los que lo hacen, varía la medida en que las metaclases pueden anular cualquier aspecto dado del comportamiento de clase. Las metaclases se pueden implementar haciendo que las clases sean ciudadanos de primera clase , en cuyo caso una metaclase es simplemente un objeto que construye clases. Cada lenguaje tiene su propio protocolo de metaobjetos , un conjunto de reglas que gobiernan cómo interactúan los objetos, las clases y las metaclases. [1]
Ejemplo de Python
En Python , la clase incorporada type
es una metaclase. [2] [3] [4] Considere esta simple clase de Python:
clase Coche : def __init__ ( self , make : str , modelo : str , año : int , color : str ): self . hacer = hacerse a sí mismo . modelo = modelo de sí mismo . año = año propio . color = color @property def description ( self ) -> str : "" "Devuelve una descripción de este auto." "" return f " { self . color } { self . year } { self . make } { self . model } "
En tiempo de ejecución, en Car
sí mismo es una instancia de type
. El código fuente de la Car
clase, que se muestra arriba, no incluye detalles como el tamaño en bytes de los Car
objetos, su diseño binario en la memoria, cómo se asignan, que el __init__
método se llama automáticamente cada vez que Car
se crea a, etc. Estos detalles entran en juego no solo cuando Car
se crea un nuevo objeto, sino también cada vez que Car
se accede a cualquier atributo de a. En idiomas sin metaclases, estos detalles están definidos por la especificación del idioma y no se pueden anular. En Python, la metaclase - type
- controla estos detalles del Car
comportamiento de. Se pueden anular utilizando una metaclase diferente en lugar de type
.
El ejemplo anterior contiene un código redundante que ver con los cuatro atributos make
, model
, year
, y color
. Es posible eliminar parte de esta redundancia utilizando una metaclase. En Python, una metaclase se define más fácilmente como una subclase de type
.
class AttributeInitType ( tipo ): def __call__ ( self , * args , ** kwargs ): "" "Crea una nueva instancia." "" # Primero, cree el objeto de la forma predeterminada normal. obj = tipo . __call__ ( self , * args ) # Además, establezca atributos en el nuevo objeto. por nombre , valor en kwargs . items (): setattr ( obj , nombre , valor ) # Devuelve el nuevo objeto. volver obj
Esta metaclase solo anula la creación de objetos. Todos los demás aspectos del comportamiento de la clase y el objeto aún son manejados por type
.
Ahora la clase Car
se puede reescribir para usar esta metaclase. En Python 3, esto se hace proporcionando un "argumento de palabra clave" metaclass
a la definición de la clase:
class Car ( objeto , metaclass = AttributeInitType ): @property def description ( self ) -> str : "" "Devuelve una descripción de este auto." "" return "" . join ( str ( valor ) para el valor en sí mismo . __dict__ . valores ())
El objeto resultante Car
se puede instanciar como de costumbre, pero puede contener cualquier número de argumentos de palabras clave:
new_car = Coche ( marca = 'Toyota' , modelo = 'Prius' , año = 2005 , color = 'Verde' , motor = 'Híbrido' )
En Smalltalk-80
En Smalltalk , todo es un objeto . Además, Smalltalk es un sistema basado en clases , lo que significa que cada objeto tiene una clase que define la estructura de ese objeto (es decir, las variables de instancia que tiene el objeto) y los mensajes que comprende. En conjunto, esto implica que una clase en Smalltalk es un objeto y que, por lo tanto, una clase debe ser una instancia de una clase (llamada metaclase).
Como ejemplo, un objeto de automóvil c
es una instancia de la clase Car
. A su vez, la clase Car
es nuevamente un objeto y, como tal, una instancia de la metaclase de Car
llamado Car class
. Tenga en cuenta el espacio en blanco en el nombre de la metaclase. El nombre de la metaclase es la expresión de Smalltalk que, cuando se evalúa, da como resultado el objeto de la metaclase. Por lo tanto, evaluar los Car class
resultados en el objeto de la metaclase Car
cuyo nombre es Car class
(se puede confirmar esto evaluando Car class name
cuál devuelve el nombre de la metaclase de Car
).
Los métodos de clase pertenecen en realidad a la metaclase, al igual que los métodos de instancia pertenecen en realidad a la clase. Cuando se envía un mensaje al objeto 2
, la búsqueda del método comienza en Integer
. Si no se encuentra, avanza por la cadena de superclase, deteniéndose en Objeto, ya sea que se encuentre o no.
Cuando se envía un mensaje a Integer
la búsqueda, el método comienza en Integer class
y continúa hacia arriba en la cadena de superclase Object class
. Tenga en cuenta que, hasta ahora, la cadena de herencia de la metaclase sigue exactamente a la cadena de herencia de la clase. Pero la cadena de la metaclase se extiende más allá porque Object class
es la subclase de Class
. Todas las metaclases son subclases de Class.
En los primeros Smalltalks, solo se llamaba una metaclase Class
. Esto implicaba que los métodos de todas las clases han eran los mismos, en particular el método para crear nuevos objetos, es decir, new
. Para permitir que las clases tengan sus propios métodos y sus propias variables de instancia (llamadas variables de instancia de clase y no deben confundirse con variables de clase ), Smalltalk-80 introdujo para cada clase C
su propia metaclase C class
. Esto significa que cada metaclase es efectivamente una clase singleton .
Dado que no existe el requisito de que las metaclases se comporten de manera diferente entre sí, todas las metaclases son instancias de una sola clase llamada Metaclass
. Se Metaclass
llama a la metaclase de, Metaclass class
que de nuevo es una instancia de clase Metaclass
.
En Smalltalk-80, cada clase (excepto Object
) tiene una superclase . La superclase abstracta de todas las metaclases es Class
, que describe la naturaleza general de las clases.
La jerarquía de superclase para las metaclases es paralela a la de las clases, excepto para la clase Object
. TODAS las metaclases son subclases de Class
, por lo tanto:
Object class superclass == Class.
Al igual que los gemelos unidos , las clases y las metaclases nacen juntas. Metaclass
tiene una variable de instancia thisClass
, que apunta a su clase conjunta. Tenga en cuenta que el navegador de clases Smalltalk habitual no muestra las metaclases como clases separadas. En cambio, el navegador de clases permite editar la clase junto con su metaclase al mismo tiempo.
Los nombres de las clases en la jerarquía de la metaclase se confunden fácilmente con los conceptos del mismo nombre. Por ejemplo:
Object
es la clase base que proporciona métodos comunes para todos los objetos; "un objeto" es un número entero, un widget, unCar
, etc.Class
es la base de las metaclases que proporciona métodos comunes para todas las clases (aunque no es una metaclase en sí); "una clase" es algo comoInteger
, oWidget
, oCar
, etc.Metaclass
proporciona métodos comunes para todas las metaclases.
Cuatro clases proporcionan las facilidades para describir nuevas clases. Su jerarquía de herencia (de Object) y las principales facilidades que brindan son:
- Objeto: comportamiento predeterminado común a todos los objetos, como el acceso a clases
- Comportamiento: estado mínimo para compilar métodos y crear / ejecutar objetos
- ClassDescription ( clase abstracta ) - nombres de clases / variables, comentarios
- Clase: instalaciones similares y más completas a las superclases
- Metaclase: inicialización de variables de clase, mensajes de creación de instancias
- ClassDescription ( clase abstracta ) - nombres de clases / variables, comentarios
- Comportamiento: estado mínimo para compilar métodos y crear / ejecutar objetos
En rubí
Ruby purifica el concepto Smalltalk-80 de metaclases al introducir clases propias , eliminar la Metaclass
clase y ( des ) redefinir el mapa de clase de. El cambio se puede esquematizar de la siguiente manera: [5]
| → |
|
Nótese en particular la correspondencia entre las metaclases implícitas de Smalltalk y las autoclases de clases de Ruby. El modelo de clase propia de Ruby hace que el concepto de metaclases implícitas sea completamente uniforme: cada objeto x tiene su propio metaobjeto, llamado la clase propia de x , que es un metanivel más alto que x . Las autoclases de "orden superior" generalmente existen de forma puramente conceptual: no contienen ningún método ni almacenan ningún (otro) dato en la mayoría de los programas de Ruby. [6]
Los siguientes diagramas muestran una estructura central de muestra de Smalltalk-80 y Ruby en comparación. [7] En ambos lenguajes, la estructura consta de una parte incorporada que contiene los objetos circulares (es decir, objetos que aparecen en un ciclo formado por una combinación de enlaces azules o verdes) y una parte de usuario que tiene cuatro objetos explícitos: clases A
y B
objetos terminales u
y v
. Los enlaces verdes muestran la relación de herencia hijo → padre (con la dirección ascendente implícita), los enlaces azules muestran la relación de instanciación miembro → contenedor complementario (un enlace azul desde x apunta al contenedor menos real de x que es el punto de inicio para el búsqueda de método cuando se invoca un método en x ). Los nodos grises muestran las autoclases (resp. Metaclases implícitas en el caso de Smalltalk-80).
Smalltalk-80 | Rubí | |
El diagrama de la derecha también proporciona una imagen de la evaluación perezosa de clases propias en Ruby. El v
objeto puede tener su clase propia evaluada (asignada) como consecuencia de agregar métodos singleton a v
.
De acuerdo con el método de introspección de Ruby nombrado class
, la clase de cada clase (y de cada clase propia) es constantemente la Class
clase (indicada por c
en el diagrama). Class
, y Struct
son las únicas clases que tienen clases como instancias. [8] [ disputado ] NoClass
se permite la subclasificación de . Siguiendo la definición estándar de metaclases podemos concluir que Class
y Struct
son las únicas metaclases en Ruby. Esto parece contradecir la correspondencia entre Ruby y Smalltalk, ya que en Smalltalk-80, cada clase tiene su propia metaclase. La discrepancia se basa en el desacuerdo entre el class
método de introspección en Ruby y Smalltalk. Mientras que el mapa x ↦ x. class
coincide en objetos terminales, se diferencia en la restricción a clases. Como ya se mencionó anteriormente, para una clase x
, la expresión de Ruby x.class
evalúa constantemente a Class
. En Smalltalk-80, si x
es una clase, entonces la expresión x class
corresponde a Ruby, x.singleton_class
que se evalúa como la clase propia de x
.
En Objective-C
Las metaclases de Objective-C son casi las mismas que las de Smalltalk-80, lo que no es sorprendente ya que Objective-C toma mucho prestado de Smalltalk. Al igual que Smalltalk, en Objective-C, las variables de instancia y los métodos están definidos por la clase de un objeto. Una clase es un objeto, por lo tanto, es una instancia de una metaclase.
Al igual que Smalltalk, en Objective-C, los métodos de clase son simplemente métodos llamados en el objeto de clase, por lo tanto, los métodos de clase de una clase deben definirse como métodos de instancia en su metaclase. Debido a que diferentes clases pueden tener diferentes conjuntos de métodos de clase, cada clase debe tener su propia metaclase separada. Las clases y metaclases siempre se crean como un par: el tiempo de ejecución tiene funciones objc_allocateClassPair()
y objc_registerClassPair()
para crear y registrar pares clase-metaclase, respectivamente.
No hay nombres para las metaclases; sin embargo, se puede hacer referencia a un puntero a cualquier objeto de clase con el tipo genérico Class
(similar al tipo que id
se usa para un puntero a cualquier objeto).
Debido a que los métodos de clase se heredan a través de la herencia, como Smalltalk, las metaclases deben seguir un esquema de herencia paralelo al de las clases (por ejemplo, si la clase principal de la clase A es la clase B, entonces la clase principal de la metaclase A es la metaclase B), excepto la de la clase raíz.
A diferencia de Smalltalk, la metaclase de la clase raíz hereda de la clase raíz (generalmente NSObject
usando el marco Cocoa ). Esto asegura que todos los objetos de clase sean, en última instancia, instancias de la clase raíz, de modo que pueda utilizar los métodos de instancia de la clase raíz, generalmente métodos de utilidad útiles para objetos, en los propios objetos de clase.
Dado que los objetos de metaclase no se comportan de manera diferente (no se pueden agregar métodos de clase para una metaclase, por lo que los objetos de metaclase tienen todos los mismos métodos), todos son instancias de la misma clase, la metaclase de la clase raíz (a diferencia de Smalltalk). Por tanto, la metaclase de la clase raíz es una instancia de sí misma. La razón de esto es que todas las metaclases heredan de la clase raíz; por lo tanto, deben heredar los métodos de clase de la clase raíz. [9]
Soporte en idiomas y herramientas
Los siguientes son algunos de los lenguajes de programación más destacados que admiten metaclases.
- Common Lisp , a través de CLOS
- Delphi y otras versiones de Object Pascal influenciadas por él
- Groovy
- C objetivo
- Pitón
- Perl , a través del pragma de la metaclase, así como Moose
- Rubí
- Charla
- C ++ (planeado para C ++ 23 ) [10]
Algunos lenguajes menos extendidos que admiten metaclases incluyen OpenJava , OpenC ++ , OpenAda , CorbaScript , ObjVLisp , Object-Z , MODEL-K , XOTcl y MELDC . Varios de estos idiomas datan de principios de la década de 1990 y son de interés académico. [11]
Logtalk , una extensión de Prolog orientada a objetos , también admite metaclases.
El marco de descripción de recursos (RDF) y el lenguaje de modelado unificado (UML) admiten metaclases.
Ver también
- Metamodelo
- Metaprogramación
- Metaobjeto
- Tipo (teoría de tipos)
- Reflexión
- Dinamismo
- Patrón de adaptador
- Metaclase (Web semántica)
- ¿Qué es una metaclase?
Referencias
- ^ Ira R. Forman y Scott Danforth (1999). Poniendo a trabajar las metaclases . ISBN 0-201-43305-2.
- ^ Programación IBM Metaclass en Python, partes 1 Archivado 2008-09-03 en Wayback Machine , 2 y 3
- ^ Foro Artima: Metaclases en Python 3.0 (parte 1 de 2) (parte 2 de 2)
- ^ David Mertz. "Una introducción a la programación de Python Metaclass" . ONLamp . Archivado desde el original el 30 de abril de 2003 . Consultado el 28 de junio de 2006 .
- ^ "El modelo de objeto Ruby: comparación con Smalltalk-80" .
- ^ Paolo Perrotta (2010). Metaprogramación de Ruby . Estantería pragmática. ISBN 978-1-934356-47-0.
- ^ "Pertenencia a objetos: la estructura básica de la tecnología de objetos" .
- ^ "Estructura" . Ruby Doc . Consultado el 1 de mayo de 2015 .
- ^ Cocoa with Love: ¿Qué es una metaclase en Objective-C?
- ^ Herb Sutter . "Metaclases" (PDF) .
- ^ "Una implementación de mixins en Java usando metaclases" (PDF) . Archivado desde el original (PDF) el 16 de octubre de 2007 . Consultado el 27 de noviembre de 2007 .