En la programación orientada a objetos , una metaclase es una clase cuyas definiciones sintácticas se utilizan para la definición sintáctica de las clases mismas. A diferencia de las clases ordinarias, que definen el comportamiento de los objetos, las metaclases especifican el comportamiento de las clases y sus instancias. No todos los lenguajes de programación orientada a objetos admiten el concepto de metaclases. En aquellos que sí lo hacen, el grado de control que las metaclases tienen sobre el comportamiento de las clases varía. Las metaclases a menudo se implementan tratando a las clases como ciudadanos de primera clase , convirtiendo una metaclase en un objeto que crea y gestiona estas clases. Cada lenguaje de programación se adhiere a su propio protocolo de metaobjetos , que son las reglas que determinan las interacciones entre objetos, clases y metaclases. [ 1 ] Las metaclases se utilizan para automatizar la generación de código y para mejorar el desarrollo de frameworks. [ 2 ]
Ejemplo de Python
En Python , la clase integrada typees una metaclase. [ 3 ] [ 4 ] [ 5 ] Considere esta sencilla clase de Python:
Clase Coche : marca : str modelo : str año : int color : strdef __init__ ( self , make : str , model : str , year : int , color : str ) -> None : self . make = make self . model = model self . year = year self . color = color@property def description ( self ) -> str : """ Devuelve una descripción de este coche. """ return f " { self . color } { self . make } { self . model } "En tiempo de ejecución, Cares una instancia de type. El código fuente de la Carclase, mostrado arriba, no incluye detalles como el tamaño en bytes de Carlos objetos, su disposición binaria en memoria, cómo se asignan, que el __init__método se llama automáticamente cada vez Carque se crea un , etc. Estos detalles entran en juego no solo cuando Carse crea un nuevo objeto, sino también cada vez que Carse accede a cualquier atributo de un . En lenguajes sin metaclases, estos detalles están definidos por la especificación del lenguaje y no se pueden sobrescribir. En Python, la metaclase - type- controla estos detalles del Carcomportamiento de . Se pueden sobrescribir usando una metaclase diferente en lugar de type.
El ejemplo anterior contiene código redundante relacionado con los cuatro atributos make, model, year, y color. Es posible eliminar parte de esta redundancia utilizando una metaclase personalizada. En Python, una metaclase se define más fácilmente como una subclase de type.
from typing import Anyclase AttributeInitType ( tipo ): def __call__ ( self , * args : tuple [ Any ], ** kwargs : dict [ str , Any ]) -> object : """ Crea una nueva instancia. """# Primero, crea el objeto de la forma predeterminada normal. obj : object = type .__ call__ ( self , * args )# Además, establece los atributos en el nuevo objeto. para nombre , valor en kwargs.items ( ) : setattr ( obj , nombre , valor )# Devuelve el nuevo objeto. return objEsta metaclase solo anula la creación de objetos. Todos los demás aspectos del comportamiento de la clase y del objeto siguen siendo gestionados por type.
Ahora se puede reescribir la clase Carpara usar esta metaclase. En Python 3, esto se hace proporcionando un "argumento de palabra clave" metaclassa la definición de la clase:
clase Car ( objeto , metaclass = AttributeInitType ): @property def description ( self ) -> str : """ Devuelve una descripción de este coche. """ return " " . join ( str ( value ) for value in self . __dict__ . values ())El objeto resultante Carse puede instanciar como de costumbre, pero puede contener cualquier número de argumentos con nombre:
nuevo_coche : Coche = 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 su estructura (es decir, las variables de instancia que posee) y los mensajes que entiende. En conjunto, esto implica que una clase en Smalltalk es un objeto y que, por lo tanto, una clase debe ser una instancia de otra clase (denominada metaclase).
Por ejemplo, un objeto de coche ces una instancia de la clase Car. A su vez, la clase Cares de nuevo un objeto y, como tal, una instancia de la metaclase de Carllamada Car class. Nótese el espacio en blanco en el nombre de la metaclase. El nombre de la metaclase es la expresión de Smalltalk que, al evaluarse, da como resultado el objeto de metaclase. Así, al evaluar Car classse obtiene el objeto de metaclase Carcuyo nombre es Car class(esto se puede confirmar evaluando , Car class nameque devuelve el nombre de la metaclase de Car).
Los métodos de clase pertenecen a la metaclase, al igual que los métodos de instancia pertenecen 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, continúa ascendiendo por la cadena de superclases, deteniéndose en Object, independientemente de si se encuentra o no.
Cuando se envía un mensaje, Integerla búsqueda del método comienza en Integer classy continúa ascendiendo por la cadena de superclases hasta Object class. Nótese que, hasta ahora, la cadena de herencia de metaclases sigue exactamente la de la cadena de herencia de clases. Pero la cadena de metaclases se extiende más allá porque Object classes la subclase de Class. Todas las metaclases son subclases de Class.
En las primeras versiones de Smalltalk, solo existía una metaclase llamada Class. Esto implicaba que los métodos de todas las clases eran los mismos, en particular el método para crear nuevos objetos, es decir, new. Para permitir que las clases tuvieran sus propios métodos y sus propias variables de instancia (denominadas variables de instancia de clase y que no deben confundirse con las variables de clase ), Smalltalk-80 introdujo para cada clase Csu propia metaclase C class. Esto significa que cada metaclase es, en efecto, una clase singleton .
Dado que no existe ningún requisito de que las metaclases se comporten de manera diferente entre sí, todas las metaclases son instancias de una sola clase llamada Metaclass. La metaclase de Metaclassse llama Metaclass classque, a su vez, es una instancia de la 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 superclases para 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.
Como gemelos siameses , las clases y las metaclases nacen juntas. Metaclasstiene una variable de instancia thisClassque apunta a su clase asociada. Cabe destacar que el explorador de clases habitual de Smalltalk no muestra las metaclases como clases separadas. En cambio, permite editar la clase junto con su metaclase simultáneamente.
Los nombres de las clases en la jerarquía de metaclases se confunden fácilmente con los conceptos del mismo nombre. Por ejemplo:
Objectes la clase base que proporciona métodos comunes para todos los objetos; "un objeto" es un entero, o un widget, o unCar, etc.Classes la base de las metaclases que proporciona métodos comunes para todas las clases (aunque no es una metaclase en sí misma); "una clase" es algo comoInteger, oWidget, oCar, etc.MetaclassProporciona métodos comunes para todas las metaclases.
Cuatro clases proporcionan las funcionalidades para describir nuevas clases. Su jerarquía de herencia (desde Object) y las principales funcionalidades que proporcionan 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.
- Descripción de la clase ( clase abstracta ): nomenclatura de clases/variables, comentarios
- Clase: instalaciones similares, pero más completas, a las de las superclases.
- Metaclase: inicialización de variables de clase, mensajes de creación de instancias
- Descripción de la clase ( clase abstracta ): nomenclatura de clases/variables, comentarios
- Comportamiento: estado mínimo para compilar métodos y crear/ejecutar objetos.
En Ruby
Ruby purifica el concepto de metaclases de Smalltalk-80 al introducir eigenclasses , eliminar la Metaclassclase y (des)redefinir el mapa de clase. El cambio se puede esquematizar de la siguiente manera: [ 6 ]
Nótese en particular la correspondencia entre las metaclases implícitas de Smalltalk y las eigenclases de clases de Ruby. El modelo de eigenclases de Ruby uniformiza completamente el concepto de metaclases implícitas: cada objeto x tiene su propio metaobjeto, llamado eigenclase de x , que es un metanivel superior a x . Las eigenclases de "orden superior" suelen existir puramente conceptualmente; no contienen ningún método ni almacenan ningún otro dato en la mayoría de los programas Ruby. [ 7 ]
Los siguientes diagramas muestran una estructura central de ejemplo de Smalltalk-80 y Ruby en comparación. [ 8 ] En ambos lenguajes, la estructura consta de una parte integrada 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 Ay B y objetos terminales uy v. Los enlaces verdes muestran la relación hijo→padre de herencia (con la dirección ascendente implícita), los enlaces azules muestran la relación miembro→contenedor complementaria de instanciación (un enlace azul desde x apunta al contenedor real más pequeño de x que es el punto de inicio para la búsqueda del método cuando se invoca un método en x ). Los nodos grises muestran las eigenclases (respectivamente, metaclases implícitas en el caso de Smalltalk-80).
El diagrama de la derecha también proporciona una imagen de la evaluación perezosa de las clases propias en Ruby. El vobjeto puede tener su clase propia evaluada (asignada) como consecuencia de agregar métodos singleton a v.
Según el método de introspección de Ruby llamado class, la clase de cada clase (y de cada eigenclass) es constantemente la Classclase (denotada por cen el diagrama). Class, y Structson las únicas clases que tienen clases como instancias. [ 9 ] No se permite la creación de subclases de . Siguiendo la definición estándar de metaclases, podemos concluir que y 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 método de introspección en Ruby y Smalltalk. Si bien el map x ↦ x. coincide en objetos terminales, difiere en la restricción a clases. Como ya se mencionó anteriormente, para una clase , la expresión de Ruby se evalúa constantemente a . En Smalltalk-80, si es una clase, entonces la expresión corresponde a la de Ruby , que se evalúa a la eigenclass de .ClassClassStructclassclassxx.classClassxx classx.singleton_classx
En Objective-C

Las metaclases en Objective-C son prácticamente idénticas a las de Smalltalk-80, lo cual no sorprende, ya que Objective-C toma prestados muchos elementos de Smalltalk. Al igual que en Smalltalk, en Objective-C las variables de instancia y los métodos se definen mediante la clase de un objeto. Una clase es un objeto y, por lo tanto, es una instancia de una metaclase.
Al igual que en Smalltalk, en Objective-C, los métodos de clase son simplemente métodos que se invocan sobre el objeto de la clase; por lo tanto, los métodos de clase de una clase deben definirse como métodos de instancia en su metaclase. Dado que las distintas clases pueden tener diferentes conjuntos de métodos de clase, cada clase debe tener su propia metaclase independiente. Las clases y las metaclases siempre se crean en pares: el entorno de ejecución dispone de funciones objc_allocateClassPair()para objc_registerClassPair()crear y registrar pares de 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 idque se usa para un puntero a cualquier objeto).
Dado que los métodos de clase se heredan mediante herencia, al igual que en Smalltalk, las metaclases deben seguir un esquema de herencia paralelo al de las clases (por ejemplo, si la clase padre de la clase A es la clase B, entonces la clase padre de la metaclase de A es la metaclase de B), excepto el de la clase raíz.
Unlike Smalltalk, the metaclass of the root class inherits from the root class (usually NSObject using the Cocoa framework) itself. This ensures that all class objects are ultimately instances of the root class, so that you can use the instance methods of the root class, usually useful utility methods for objects, on class objects themselves.
Since metaclass objects do not behave differently (you cannot add class methods for a metaclass, so metaclass objects all have the same methods), they are all instances of the same class—the metaclass of the root class (unlike Smalltalk). Thus, the metaclass of the root class is an instance of itself. The reason for this is that all metaclasses inherit from root class; hence, they must inherit the class methods of the root class.[10]
C++ proposal
Herb Sutter of the ISO C++ Committee, first proposed the inclusion of metaclasses to C++ for C++20 using C++17 features.[11] With the adoption of reflection in C++26, this paper was revised.[12]
Its primary goal is to expand C++ abstraction beyond defined vocabulary (class, struct, union, enum, etc.) to allow adoptable vocabulary (such as interface, value), for the purpose of a more liberal approach to programming free of rule-memorisation. This feature would also allow non-standard features (such as interfaces) to be expressed as core features within libraries, and eliminate the necessity of specialised compilers (such as Qt moc, C++/CX, etc.) to express specific information using standardised features.
Using code injection (another proposed addition to C++ reflection which would add token sequence injection into source code)[13], one would be able to create a Java/C# style "interface" using a consteval function:
importstd;usingstd::string;usingstd::string_view;usingstd::meta::exception;usingstd::meta::info;[[ nodiscard ]] consteval info makeInterfaceFunctions ( info proto ) noexcept { info ret = ^^ {}; for ( info mem : std :: meta :: members_of ( proto )) { if ( std :: meta :: is_nonspecial_member_function ( mem )) { ret = ^^ { \ tokens ( ret ) virtual [ : \ ( std :: meta :: return_type_of ( mem )) : ] \ id ( std :: meta :: identifier_of ( mem )) ( \ tokens ( std :: meta :: parameter_list_of ( mem ))) = 0 ; }; } else if ( std :: meta :: is_variable ( mem )) { // Nota: esto es std::meta::exception, no std::exception throw exception ( "Variable encontrada en el prototipo" , ^^ makeInterfaceFunctions ); } } return ret ; }consteval void interface ( info proto ) noexcept { string_view name = std :: meta :: identifier_of ( proto ); std :: meta :: queue_injection ( ^^ { class \ id ( name ) { public : // crear funciones de interfaz \ tokens ( makeInterfaceFunctions ( proto )) // el destructor virtual ~ \ id ( name )() = default ; // el constructor \ id ( name )() = default ; // eliminar el constructor de copia \ id ( name )( const \ id ( name ) & ) = delete ; // eliminar el operador de asignación de copia void operator = ( const \ id ( name ) & ) = delete ; }; }); }// usar "interface": class ( interface ) IFoo { int f (); void g ( string s ); };También sería posible aplicar varios tipos de metaclases. Por ejemplo, para las metaclases xy y, se podría escribir .class(x,y)MyClass{/* ... */};
El artículo propone que esto permite que las abstracciones reduzcan considerablemente el código repetitivo mediante la generación de funciones y la personalización de valores predeterminados, semántica y restricciones. Además, elimina la necesidad de crear nuevas propuestas de características del lenguaje, al permitir que dichas características se expresen mediante características de metaclase.
Soporte en idiomas y herramientas
A continuación se presentan algunos de los lenguajes de programación más destacados que admiten metaclases.
- Common Lisp , vía CLOS
- Delphi y otras versiones de Object Pascal influenciadas por él
- Genial
- Objetivo-C
- ooRexx
- Pitón
- Perl , a través de la pragma metaclass, así como Moose
- Rubí
- Charla informal
Algunos lenguajes menos extendidos que admiten metaclases incluyen OpenJava [ 14 ] , OpenC++ [ 15 ] [ 16 ] , OpenAda , CorbaScript , ObjVLisp , Object-Z , MODEL-K , XOTcl y MELDC . Varios de estos lenguajes datan de principios de la década de 1990 y son de interés académico. [ 17 ]
Funcionalidades de Javajava.lang.Class<T> para la introspección , similares a las metaclases, pero que en realidad no son metaclases.
Logtalk , una extensión orientada a objetos de Prolog , también admite metaclases.
Tanto el Marco de Descripción de Recursos (RDF) como el Lenguaje Unificado de Modelado (UML) admiten metaclases.
Las metaclases fueron propuestas para una posible inclusión en futuras versiones de C++ , pero actualmente no son una característica incluida. [ 11 ]
Véase también
Referencias
- ↑ Forman, Ira R.; Danforth, Scott (1999). Poniendo las metaclases en práctica . Addison-Wesley. ISBN 0-201-43305-2.
- ↑ AloorRavi, Sulekha (2022). Metaprogramación con Python . Birmingham: Packt Publishing.
- ↑ Programación de metaclases de IBM en Python, partes 1 Archivado el 3 de septiembre de 2008 en Wayback Machine , 2 Archivado el 23 de agosto de 2008 en Wayback Machine y 3 Archivado el 21 de marzo de 2009 en Wayback Machine
- ↑ Foro de Artima: Metaclases en Python 3.0 (parte 1 de 2) Archivado el 24 de septiembre de 2020 en Wayback Machine (parte 2 de 2) Archivado el 9 de abril de 2016 en Wayback Machine
- ↑ Mertz, David. "Introducción a la programación con metaclases en Python" . ONLamp . Archivado del original el 30 de abril de 2003. Consultado el 28 de junio de 2006 .
- ↑ "El modelo de objetos de Ruby: comparación con Smalltalk-80" . Archivado del original el 17 de enero de 2020. Consultado el 10 de febrero de 2012 .
- ↑ Perrotta, Paolo (2010). Metaprogramming Ruby . Pragmatic Bookshelf. ISBN 978-1-934356-47-0Archivado del original el 9 de junio de 2016. Consultado el 21 de noviembre de 2013 .
- ↑ "Membresía de objetos: La estructura central de la tecnología de objetos" . Archivado del original el 6 de mayo de 2021. Recuperado el 24 de agosto de 2012 .
- ↑ "Estructura" . Archivado del original el 3 de mayo de 2025. Consultado el 28 de abril de 2025 .
- ↑ "¿Qué es una metaclase en Objective-C?" . Cocoa with Love . 17 de enero de 2010. Archivado del original el 6 de agosto de 2011. Consultado el 22 de julio de 2011 .
- 1 2 Sutter, Herb (18 de junio de 2017). "P0707 R0 - Metaclasses" (PDF) . open-std.org . WG21. Archivado (PDF) del original el 11 de noviembre de 2020. Recuperado el 8 de agosto de 2018 .
- ↑ Sutter, Herb (12 de octubre de 2024). "Creación declarativa de clases usando funciones constantes + reflexión + generación (también conocidas como: Metaclases para C++ generativo)" (PDF) . open-std.org . WG21 . Consultado el 14 de diciembre de 2025 .
- ↑ Andrei Alexandrescu, Barry Rezvin, Daveed Vandevoorde (16 de julio de 2024). "Inyección de código con secuencias de tokens" . open-std.org . WG21.
{{cite web}}: CS1 maint: varios nombres: lista de autores ( enlace ) - ^ Michiaki Tatsubori (14 de octubre de 2007). "DO: un Java extensible" . csg.ci.iu-tokyo.ac.jp . Universidad de Tokio. Archivado desde el original el 13 de agosto de 2014.
- ↑ Shigeru Chiba (14 de octubre de 2007). "Página principal de OpenC++" . csg.ci.iu-tokyo.ac.jp . Universidad de Tokio. Archivado del original el 21 de agosto de 2014.
- ↑ Shigeru Chiba. "Bienvenido a OpenC++" . opencxx.sourceforge.net . Universidad de Tokio . Consultado el 10 de diciembre de 2025 .
- ↑ "Una implementación de mixins en Java usando metaclasses" (PDF) . Archivado del original (PDF) el 16 de octubre de 2007. Recuperado el 27 de noviembre de 2007 .
Enlaces externos
- ¿Qué es una metaclase?
- Clase (programación informática)
