Recent from talks
Nothing was collected or created yet.
Metaclass
View on WikipediaThis article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these messages)
|
In object-oriented programming, a metaclass is a class whose instances are classes themselves. Unlike ordinary classes, which define the behaviors of objects, metaclasses specify the behaviors of classes and their instances. Not all object-oriented programming languages support the concept of metaclasses. For those that do, the extent of control metaclasses have over class behaviors varies. Metaclasses are often implemented by treating classes as first-class citizens, making a metaclass an object that creates and manages these classes. Each programming language adheres to its own metaobject protocol, which are the rules that determine interactions among objects, classes, and metaclasses.[1] Metaclasses are utilized to automate code generation and to enhance framework development.[2]
Python example
[edit]In Python, the builtin class type is a metaclass.[3][4][5] Consider this simple Python class:
class Car:
make: str
model: str
year: int
color: str
def __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:
"""
Return a description of this car.
"""
return f"{self.color} {self.make} {self.model}"
At run time, Car itself is an instance of type. The source code of the Car class, shown above, does not include such details as the size in bytes of Car objects, their binary layout in memory, how they are allocated, that the __init__ method is automatically called each time a Car is created, and so on. These details come into play not only when a new Car object is created, but also each time any attribute of a Car is accessed. In languages without metaclasses, these details are defined by the language specification and can't be overridden. In Python, the metaclass - type - controls these details of Car's behavior. They can be overridden by using a different metaclass instead of type.
The above example contains some redundant code to do with the four attributes make, model, year, and color. It is possible to eliminate some of this redundancy using a custom metaclass. In Python, a metaclass is most easily defined as a subclass of type.
from typing import Any, Dict, Tuple
class AttributeInitType(type):
def __call__(self, *args: Tuple[Any], **kwargs: Dict[str, Any]) -> object:
"""
Create a new instance.
"""
# First, create the object in the normal default way.
obj: object = type.__call__(self, *args)
# Additionally, set attributes on the new object.
for name, value in kwargs.items():
setattr(obj, name, value)
# Return the new object.
return obj
This metaclass only overrides object creation. All other aspects of class and object behavior are still handled by type.
Now the class Car can be rewritten to use this metaclass. In Python 3 this is done by providing a "keyword argument" metaclass to the class definition:
class Car(object, metaclass=AttributeInitType):
@property
def description(self) -> str:
"""
Return a description of this car.
"""
return " ".join(str(value) for value in self.__dict__.values())
The resulting object Car can be instantiated as usual, but can contain any number of keyword arguments:
new_car: Car = Car(make='Toyota', model='Prius', year=2005, color='Green', engine='Hybrid')
In Smalltalk-80
[edit]

In Smalltalk, everything is an object. Additionally, Smalltalk is a class based system, which means that every object has a class that defines the structure of that object (i.e. the instance variables the object has) and the messages an object understands. Together this implies that a class in Smalltalk is an object and that, therefore a class needs to be an instance of a class (called metaclass).
As an example, a car object c is an instance of the class Car. In turn, the class Car is again an object and as such an instance of the metaclass of Car called Car class. Note the blank in the name of the metaclass. The name of the metaclass is the Smalltalk expression that, when evaluated, results in the metaclass object. Thus evaluating Car class results in the metaclass object for Car whose name is Car class (one can confirm this by evaluating Car class name which returns the name of the metaclass of Car.)
Class methods actually belong to the metaclass, just as instance methods actually belong to the class. When a message is sent to the object 2, the search for the method starts in Integer. If it is not found it proceeds up the superclass chain, stopping at Object whether it is found or not.
When a message is sent to Integer the search for the method starts in Integer class and proceeds up the superclass chain to Object class. Note that, so far, the metaclass inheritance chain exactly follows that of the class inheritance chain. But the metaclass chain extends further because Object class is the subclass of Class. All metaclasses are subclasses of Class.
In early Smalltalks, there was only one metaclass called Class. This implied that the methods all classes have were the same, in particular the method to create new objects, i.e., new. To allow classes to have their own methods and their own instance variables (called class instance variables and should not be confused with class variables), Smalltalk-80 introduced for each class C their own metaclass C class. This means that each metaclass is effectively a singleton class.
Since there is no requirement that metaclasses behave differently from each other, all metaclasses are instances of only one class called Metaclass. The metaclass of Metaclass is called Metaclass class which again is an instance of class Metaclass.
In Smalltalk-80, every class (except Object) has a superclass. The abstract superclass of all metaclasses is Class, which describes the general nature of classes.
The superclass hierarchy for metaclasses parallels that for classes, except for class Object. ALL metaclasses are subclasses of Class, therefore:
Object class superclass == Class.
Like conjoined twins, classes and metaclasses are born together. Metaclass has an instance variable thisClass, which points to its conjoined class.
Note that the usual Smalltalk class browser does not show metaclasses as separate classes. Instead the class browser allows to edit the class together with its metaclass at the same time.
The names of classes in the metaclass hierarchy are easily confused with the concepts of the same name. For instance:
Objectis the base class that provides common methods for all objects; "an object" is an integer, or a widget, or aCar, etc.Classis the base of the metaclasses that provides common methods for all classes (though it is not a metaclass itself); "a class" is something likeInteger, orWidget, orCar, etc.Metaclassprovides common methods for all metaclasses.
Four classes provide the facilities to describe new classes. Their inheritance hierarchy (from Object), and the main facilities they provide are:
- Object - default behavior common to all objects, like class access
- Behavior - minimum state for compiling methods and creating/running objects
- ClassDescription (abstract class) - class/variable naming, comments
- Class - similar, more comprehensive, facilities to superclasses
- Metaclass - initializing class variables, instance creation messages
- ClassDescription (abstract class) - class/variable naming, comments
- Behavior - minimum state for compiling methods and creating/running objects
In Ruby
[edit]Ruby purifies the Smalltalk-80 concept of metaclasses by introducing eigenclasses,
removing the Metaclass class,
and (un)redefining the class-of map.
The change can be schematized as follows:[6]
|
→ |
|
Note in particular the correspondence between Smalltalk's implicit metaclasses and Ruby's eigenclasses of classes. The Ruby eigenclass model makes the concept of implicit metaclasses fully uniform: every object x has its own meta-object, called the eigenclass of x, which is one meta-level higher than x. The "higher order" eigenclasses usually exist purely conceptually – they do not contain any methods or store any (other) data in most Ruby programs.[7]
The following diagrams show a sample core structure of Smalltalk-80 and Ruby in comparison.[8]
In both languages, the structure consists of a built-in part which contains the circular objects (i.e. objects that appear in a cycle formed by a combination of blue or green links) and a user-part which has four explicit objects: classes A and B
and terminal objects u and v.
Green links show the child→parent relation of inheritance (with the implicit upward direction), blue links show the complementary member→container relation of instantiation (a blue link from x points to the least actual container of x that is the start point for the method lookup when a method is invoked on x). Gray nodes display the eigenclasses (resp. implicit metaclasses in the case of Smalltalk-80).
| Smalltalk-80 | Ruby | |
The diagram on the right also provides a picture of lazy evaluation of eigenclasses in Ruby. The v object can have its eigenclass evaluated (allocated) as a consequence of adding singleton methods to v.
According to the Ruby's introspection method named class,
the class of every class (and of every eigenclass) is
constantly the Class class (denoted by c in the diagram).
Class, and Struct are the only classes that have classes as instances.[9] [disputed – discuss] Subclassing of Class is disallowed.
Following the standard definition of metaclasses we can conclude that Class and Struct are the only metaclasses in Ruby.
This seems to contradict the correspondence between Ruby and Smalltalk,
since in Smalltalk-80, every class has its own metaclass.
The discrepancy is based on the disagreement between
the class introspection method in Ruby and Smalltalk. While the map x ↦ x.class coincides on terminal objects, it differs in the restriction to classes. As already mentioned above, for a class x, the Ruby expression x.class evaluates constantly to Class. In Smalltalk-80, if x is a class then the expression x class corresponds
to the Ruby's x.singleton_class
– which evaluates to the eigenclass of x.
In Objective-C
[edit]This section needs additional citations for verification. (October 2013) |
This section's tone or style may not reflect the encyclopedic tone used on Wikipedia. (September 2013) |

Metaclasses in Objective-C are almost the same as those in Smalltalk-80—not surprising since Objective-C borrows a lot from Smalltalk. Like Smalltalk, in Objective-C, the instance variables and methods are defined by an object's class. A class is an object, hence it is an instance of a metaclass.
Like Smalltalk, in Objective-C, class methods are simply methods called on the class object, hence a class's class methods must be defined as instance methods in its metaclass. Because different classes can have different sets of class methods, each class must have its own separate metaclass. Classes and metaclasses are always created as a pair: the runtime has functions objc_allocateClassPair() and objc_registerClassPair() to create and register class-metaclass pairs, respectively.
There are no names for the metaclasses; however, a pointer to any class object can be referred to with the generic type Class (similar to the type id being used for a pointer to any object).
Because class methods are inherited through inheritance, like Smalltalk, metaclasses must follow an inheritance scheme paralleling that of classes (e.g. if class A's parent class is class B, then A's metaclass's parent class is B's metaclass), except that of the root class.
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
[edit]Herb Sutter of the ISO C++ Committee, has proposed the inclusion of metaclasses to C++ (originally for C++20 using C++17 features), though this feature has still not been included.[11]
This feature would build off of C++ concepts (constraints on types and templates), reflection, and if constexpr. Its primary goal would be 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.
Although C++26 adopted different means to represent reflection[12], the paper proposed $T to represent reflecting type T and $expr to represent reflecting an expression expr, based off of an older proposal for reflection.[13] For example, this would examine each member variable m in T for one named xyzzy, and inject an int named plugh, using a constexpr block with -> {} (for injecting code into the enclosing scope). It further proposed compiler-integrated diagnostics to emit compiler diagnostic messages (i.e. compiler.error("Some error", source_location)). Named concepts could be used to declare symbols, similar to assigning concrete classes to variables holding interface types in Java and C#.[14]
using std::meta::variable;
constexpr {
for (variable m: $T.variables()) {
if (m.name() == "xyzzy") -> { int plugh; }
}
}
For example, the following would create a metaclass called interface which would behave similar to a Java interface:
using std::meta::function;
$class interface {
~interface() noexcept {
// custom logic if necessary here...
}
constexpr {
compiler.require($interface.variables().empty(), "interfaces may not contain data");
for (function f: $interface.functions()) {
compiler.require(
!f.is_copy() && !f.is_move(),
"Interfaces may not copy or move; consider a virtual clone instead"
);
if (!f.has_access()) {
f.make_public();
}
compiler.require(f.is_public(), "Interface functions must be public");
f.make_pure_virtual();
}
}
};
// now supports (similar to Java/C#):
interface Shape {
int area() const;
void scaleBy(double factor);
};
One could similarly emulate Project Valhalla Java value classes, by creating $class value which generates comparison operators and default constructors.
It would further support ad-hoc duck typing:
$T.is(M)evaluates totrueif and only if applyingMtoTsucceeds (i.e.Talready definesM) and its resulting type has no new members not already present inT.$T.as(M)generates a type identical toTbut is additionally defined using the named metaclassM.
It would allow for "stronger typedefs": types that behave similar to the original type but are distinct types for overloading and cannot implicitly convert to/from the original type by default:
$class noop {}; // a no-op metaclass
// equivalent to: enum class Handle: int { ... };
using Handle = $int.as(noop);
The following list (but not limited to) metaclasses were proposed to be defined in the standard library:
interface: an abstract base class with all public virtual functions, no copy/move constructors or data membersbase_class: a class designed to be inherited from with no copy/move constructors or data membersorderedet al., classes which support some comparison category (such as total ordering, equality comparison, etc.)value, a value class with default constructor/destructor, copy/move constructors, comparison methods, and no virtual methods or protected membersplain_struct, sometimes called "plain old data structs" (similar to "Plain old Java objects")flag_enum, an enum for representing flags storing values corresponding to bitwise OR enumerators
The paper proposes that this allows for abstractions to greatly decrease boilerplate by producing generated functions and customisable defaults, semantics, and constraints. It further abolishes the need to create new language feature proposals by allowing such features to be expressed using metaclass features.
Support in languages and tools
[edit]The following are some of the most prominent programming languages that support metaclasses.
- Common Lisp, via CLOS
- Delphi and other versions of Object Pascal influenced by it
- Groovy
- Objective-C
- ooRexx
- Python
- Perl, via the metaclass pragma, as well as Moose
- Ruby
- Smalltalk
Some less widespread languages that support metaclasses include OpenJava, OpenC++, OpenAda, CorbaScript, ObjVLisp, Object-Z, MODEL-K, XOTcl, and MELDC. Several of these languages date from the early 1990s and are of academic interest.[15]
Java features java.lang.Class<T> for introspection, similar to metaclasses, but are not actually metaclasses.
Logtalk, an object-oriented extension of Prolog, also supports metaclasses.
Resource Description Framework (RDF) and Unified Modeling Language (UML) both support metaclasses.
Metaclasses were a proposed for a possible inclusion in future version of C++, but currently is not an included feature.[11]
See also
[edit]References
[edit]- ^ Forman, Ira R.; Danforth, Scott (1999). Putting Metaclasses to Work. Addison-Wesley. ISBN 0-201-43305-2.
- ^ AloorRavi, Sulekha (2022). Metaprogramming with Python. Birmingham: Packt Publishing.
- ^ IBM Metaclass programming in Python, parts 1 Archived 3 September 2008 at the Wayback Machine, 2 Archived 23 August 2008 at the Wayback Machine and 3 Archived 21 March 2009 at the Wayback Machine
- ^ Artima Forum: Metaclasses in Python 3.0 (part 1 of 2) Archived 24 September 2020 at the Wayback Machine (part 2 of 2) Archived 9 April 2016 at the Wayback Machine
- ^ Mertz, David. "A Primer on Python Metaclass Programming". ONLamp. Archived from the original on 30 April 2003. Retrieved 28 June 2006.
- ^ "The Ruby Object Model: Comparison with Smalltalk-80". Archived from the original on 17 January 2020. Retrieved 10 February 2012.
- ^ Perrotta, Paolo (2010). Metaprogramming Ruby. Pragmatic Bookshelf. ISBN 978-1-934356-47-0. Archived from the original on 9 June 2016. Retrieved 21 November 2013.
- ^ "Object Membership: The Core Structure of Object Technology". Archived from the original on 6 May 2021. Retrieved 24 August 2012.
- ^ "Struct". Archived from the original on 3 May 2025. Retrieved 28 April 2025.
- ^ "What is a meta-class in Objective-C?". Cocoa with Love. 17 January 2010. Archived from the original on 6 August 2011. Retrieved 22 July 2011.
- ^ a b Sutter, Herb (18 June 2017). "P0707 R0 - Metaclasses" (PDF). open-std.org. WG21. Archived (PDF) from the original on 11 November 2020. Retrieved 8 August 2018.
- ^ Childers, Wyatt; Dimov, Peter; Katz, Dan; Revzin, Barry; Sutton, Andrew; Vali, Faisal; Vandevoorde, Daveed (26 June 2024). "P2996R4 - Reflection for C++26". isocpp.org. WG21. Archived from the original on 2 October 2025. Retrieved 20 October 2025.
- ^ Vandevoorde, Daveed; Dionne, Louis (20 March 2017). "P0633R0 - Exploring the design space of metaprogramming and reflection" (PDF). open-std.org. WG21. Archived (PDF) from the original on 8 July 2025. Retrieved 20 October 2025.
- ^ Sutton, Andrew; Sutter, Herb (5 February 2017). "P0590R0 - A design for static reflection" (PDF). open-std.org. WG21. Archived (PDF) from the original on 2 August 2025. Retrieved 20 October 2025.
- ^ "An implementation of mixins in Java using metaclasses" (PDF). Archived from the original (PDF) on 16 October 2007. Retrieved 27 November 2007.
External links
[edit]Metaclass
View on Grokipedia__new__ and __init__, but custom metaclasses can override these to enforce properties like abstract base classes, automatic registration, or resource locking during class definition.[3] Key features include preparing the class namespace via __prepare__, resolving method resolution order (MRO), and executing the class body, often used in frameworks for logging, interface checking, or implementing design patterns like Singleton without explicit inheritance.[3] Languages supporting metaclasses, including Python, Smalltalk variants like Squeak, and experimental extensions in Java (e.g., MCJ), leverage them for metaprogramming, though they introduce complexities in type systems and inheritance that require careful formalization to ensure soundness.[1]
Fundamentals
Definition and Core Concepts
In object-oriented programming, a metaclass is defined as a class whose instances are themselves classes, thereby specifying the creation, structure, and behavior of those classes.[4] This positions metaclasses as a higher-order construct that governs class-level operations, distinct from the instance-level behaviors managed by regular classes.[5] Core concepts of metaclasses revolve around their role at the meta-level of abstraction, where they facilitate introspection—allowing examination of class properties and structure—and modification of class creation, such as customizing instantiation methods or enforcing class-specific constraints.[5] For example, a metaclass might intervene during class definition to add metadata or alter default behaviors, enabling dynamic extensions to the object-oriented system without altering base-level code.[4] These capabilities support reflective programming paradigms by treating classes as first-class entities that can be queried and adapted at runtime.[5] A fundamental principle is that every class is an instance of a metaclass, establishing a recursive yet foundational layer in object-oriented systems where the metaclass hierarchy mirrors and extends the regular class hierarchy.[6] This ensures uniform treatment of classes as objects, promoting consistency in how object behaviors are defined across abstraction levels.[5] To illustrate abstractly, consider a generic metaclass hierarchy: Metaclass
|
| (defines behavior of classes)
v
Class
|
| (instances are classes, e.g., Object)
v
UserClass
|
| (instances are objects)
v
Instance
Metaclass
|
| (defines behavior of classes)
v
Class
|
| (instances are classes, e.g., Object)
v
UserClass
|
| (instances are objects)
v
Instance
Distinction from Regular Classes
Regular classes in object-oriented programming serve as templates or blueprints for creating and defining the behavior of object instances, specifying their attributes, methods, and state management. In contrast, metaclasses operate at a higher level of abstraction, functioning as the "class of a class" by defining how classes themselves are created, structured, and behave. For instance, while a regular class might dictate instance initialization and method invocation for objects, a metaclass governs class instantiation, such as validating attributes during class definition or enforcing structural constraints like interfaces.[8][9] This distinction can be analogized to blueprints: a regular class is a blueprint for constructing everyday objects, whereas a metaclass is a blueprint for constructing those blueprints, enabling customization of the class creation process itself. In systems like Smalltalk, every class is an instance of its metaclass, which handles class-side behaviors such as method storage and inheritance resolution for the class object. Similarly, in Python, the built-intype metaclass (the default for all classes) oversees class object creation via hooks like __new__ and __init__, allowing interventions in namespace preparation or method resolution order (MRO) that regular classes cannot perform.[9][8][10]
Conceptually, metaclasses delineate a meta-level boundary, focusing on class-level customizations rather than instance-level logic; for example, they can dynamically add methods to classes or enforce protocols (as in Python's abc.ABCMeta for abstract base classes), but they do not directly manage object runtime behavior. This separation ensures that metaclasses enhance reflection and extensibility without encroaching on the domain of regular classes, which remain dedicated to instance orchestration.[8]
A common pitfall in understanding metaclasses arises from conflating class methods with static methods: class methods are instance methods of the metaclass, bound to the class object and receiving the class as the first argument, whereas static methods are unbound functions attached to the class namespace without access to class or instance state. This confusion can lead to unexpected binding behaviors during class customization.[11][12][13]
Metaclass Hierarchies and Inheritance
In object-oriented programming systems supporting metaclasses, the metaclass hierarchy forms a layered structure where a root metaclass, often termed a universal metaclass such asClass, serves as the superclass for all other metaclasses. This root enables metaclasses to inherit common behaviors related to class creation and introspection. Meanwhile, regular classes inherit instance behaviors from their superclasses in the standard object hierarchy, but each class is itself an instance of a metaclass, establishing a reflective chain where classes are treated as objects governed by higher-level metaclasses.[6][1]
Inheritance mechanics in metaclass hierarchies allow a subclass to automatically inherit the metaclass of its superclass, ensuring that class-level modifications propagate consistently unless explicitly overridden by specifying a new metaclass. This override alters the subclass's creation process, such as customizing initialization or method addition, while preserving the inherited metaclass's influence on related subclasses. The mechanics support meta-inheritance, where behaviors defined in a superclass's metaclass apply to subclasses, facilitating uniform policy enforcement across the hierarchy without redundant declarations.[6][1]
A generic UML-style representation of the metaclass chain illustrates this structure as follows:
Metaclass (root)
|
Class
|
UserClass (metaclass)
|
UserClass (regular class)
|
userObject (instance)
Metaclass (root)
|
Class
|
UserClass (metaclass)
|
UserClass (regular class)
|
userObject (instance)
Historical Development
Origins in Smalltalk
The concept of metaclasses emerged as part of the development of Smalltalk at Xerox PARC, where the language evolved through multiple iterations in the 1970s to realize a pure object-oriented model. While earlier versions like Smalltalk-76 treated classes as first-class objects with inheritance capabilities, the explicit metaclass mechanism was introduced in Smalltalk-80 to enable classes to have their own distinct behaviors and methods, addressing limitations in prior systems where all classes shared a uniform protocol under a single Class metaclass. This innovation was advocated by Adele Goldberg to resolve issues such as uninitialized instances created via messages likenew, allowing for customized initialization without altering the virtual machine.[15][16]
The design rationale centered on maintaining uniformity in the object model by making every class an instance of another class—its metaclass—thus treating classes themselves as manipulable objects. Dan Ingalls implemented this feature, ensuring that each metaclass is a singleton inheriting from ClassDescription, which provides shared behavior for class management while permitting class-specific methods, such as tailored instance creation protocols (e.g., Point x: 10 y: 20). This approach avoided code duplication and supported reflective capabilities, where metaclasses form a parallel hierarchy mirroring the instance class hierarchy, with Object class as the root. As Goldberg and Ingalls noted, metaclasses allowed "each class [to] be able to have its own methods," enhancing the system's extensibility without compromising its message-passing foundation.[15][16]
This introduction in Smalltalk-80, under the guidance of Alan Kay as the project's visionary leader, marked a pivotal refinement in object-oriented programming, solidifying Smalltalk's influence on the paradigm shift from procedural to object-centric designs during the late 1970s and early 1980s. By formalizing metaclasses, the system enabled dynamic manipulation of class behaviors, contributing to Smalltalk's role as a foundational language for modern OOP concepts.[15][16]
Evolution and Adoption in Other Languages
Following the foundational concepts introduced in Smalltalk during the 1970s, metaclasses began influencing other programming languages in the 1980s and 1990s, particularly those emphasizing dynamic object-oriented features. Objective-C, developed in the early 1980s by Brad Cox and Tom Love at Stepstone, incorporated metaclasses as an integral part of its runtime system from its inception.[17] In Objective-C, classes are treated as objects, with each class having an associated metaclass that handles class methods and enables dynamic dispatch for class objects themselves. This design supported patterns like class clusters, where abstract public classes mask private concrete implementations, allowing flexible subclassing without exposing internal details.[18] In the 1990s, Ruby, created by Yukihiro Matsumoto and first released in 1995, adopted a metaclass-like mechanism through eigenclasses to simplify per-object and per-class customization. Eigenclasses in Ruby function as anonymous singleton classes attached to specific objects or classes, enabling the addition of unique methods without altering the broader class hierarchy—a feature inspired by Smalltalk's reflective capabilities but streamlined for Ruby's object model. This approach facilitated metaprogramming in dynamic contexts, influencing Ruby's emphasis on developer productivity.[19] Python formalized metaclasses in version 2.2, released in December 2001, as part of unifying its type and class systems. The built-intype became the default metaclass for new-style classes, allowing developers to define custom metaclasses via the __metaclass__ attribute or inheritance to control class creation and modification at runtime. This integration marked a milestone in Python's evolution toward more powerful metaprogramming, drawing from Smalltalk and earlier experimental extensions like Python's own Extension Classes package.[20]
The spread of metaclasses significantly shaped dynamic languages throughout the 1990s and 2000s, promoting reflective and generative programming paradigms in systems like Perl (via modules like Class::MOP) and JavaScript (through prototypes and ES6 classes). However, adoption in static languages faced substantial hurdles, primarily concerns over type safety and compile-time predictability. In languages like C++, where strict typing prevents runtime alterations to class structures, full metaclasses have been proposed but not standardized; early ideas emerged in the 1990s alongside template metaprogramming, but concrete proposals, such as Herb Sutter's generative metaclasses initiative starting in 2017, highlight ongoing efforts to balance expressiveness with safety.[21] Instead, static languages often rely on alternatives like templates or reflection APIs to achieve similar effects without compromising type guarantees.
Implementations in Dynamic Languages
In Smalltalk-80
In Smalltalk-80, each class is an instance of a unique metaclass, ensuring that classes themselves are treated as objects within the system. This metaclass is automatically generated when the class is created and serves as the sole instance of the metaclass, forming a parallel hierarchy to the instance class hierarchy. For example, the classCar is an instance of Car class, which inherits from Class (the metaclass of Object) and ultimately from Metaclass. This structure allows classes to inherit metaclass behavior uniformly, such as method storage and hierarchy management, while tailoring specific behaviors at the class level.[16]
The creation of a new class and its metaclass occurs through the subclass: message sent to an existing class, specifying details like instance variables, class variables, shared pools, and category. A representative syntax is:
[Car](/page/Car) subclass: #Sedan
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Vehicles'.
[Car](/page/Car) subclass: #Sedan
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Vehicles'.
Sedan as an instance of its anonymous metaclass (Sedan class), which inherits from Car class and shares the parallel hierarchy. Metaclasses in Smalltalk-80 are anonymous by default, referenced only via the class message sent to the class (e.g., Car class), and do not require explicit naming unless customized through additional compilation or modification. This anonymity simplifies the model while allowing full object-oriented treatment of classes.[16]
Metaclasses enable the definition of class methods, which operate on the class object rather than its instances, supporting operations like instance creation and initialization. These methods are stored in the metaclass's method dictionary and looked up via the metaclass inheritance chain, mirroring instance method lookup. For instance, a class method can be defined using the compilation syntax Car class >> newWithColor: aColor, which might create and initialize a Car instance with a specified color attribute. Metaclasses inherit standard class methods from Class, such as new and subclass:, ensuring consistent system-wide behavior.[16]
A practical example of metaclass usage is implementing instance counting at the class level without altering instance behavior. This can be achieved by overriding the new method in the metaclass and using a class variable to track the count, leveraging the metaclass's isolation from instance variables. The following illustrates this for the [Car](/page/Car) class:
"Define a class variable in the metaclass for counting"
Car class compile: 'InstanceCount
^InstanceCount ifNil: [0]'.
"Override new in the metaclass"
Car class compile: 'new
InstanceCount := (InstanceCount ifNil: [0]) + 1.
^super new'.
"Query method in the metaclass"
Car class compile: 'numberOfInstances
^InstanceCount'.
"Define a class variable in the metaclass for counting"
Car class compile: 'InstanceCount
^InstanceCount ifNil: [0]'.
"Override new in the metaclass"
Car class compile: 'new
InstanceCount := (InstanceCount ifNil: [0]) + 1.
^super new'.
"Query method in the metaclass"
Car class compile: 'numberOfInstances
^InstanceCount'.
Car new increments the count via the metaclass method, and Car numberOfInstances retrieves it, demonstrating how metaclasses encapsulate class-specific state and logic independently of instances. This approach aligns with Smalltalk-80's uniform object model, where such customizations are compiled directly to the metaclass.[16]
In Python
In Python, metaclasses provide a mechanism to customize the creation and behavior of classes, integrating seamlessly with the language's type system where classes are instances of metaclasses. A class is declared with a custom metaclass using themetaclass keyword argument in the class definition, such as class MyClass(metaclass=MyMeta):, allowing the metaclass to intercept and modify the class creation process.[8] If no metaclass is specified, the default metaclass is type, which handles standard class creation by resolving the method resolution order (MRO), preparing the namespace, executing the class body, and producing the class object.[8] This explicit assignment enables developers to define metaclasses as subclasses of type to override specific aspects of class construction.
The primary methods for customizing class creation in a metaclass are __new__ and __init__. The __new__ method, inherited from type, is responsible for creating the class object itself and receives arguments including the metaclass, class name, base classes, and namespace dictionary; overriding it allows precise control over whether and how the class is instantiated, often returning a modified or entirely new class object.[8] Following successful creation via __new__, the __init__ method initializes the newly created class object with the same arguments, enabling post-creation modifications such as adding or altering class attributes without altering the core creation logic.[8] Additionally, metaclasses can override __prepare__ to customize the namespace mapping used during class body execution, defaulting to an empty ordered dictionary for predictable attribute ordering.[8]
A representative use of metaclasses is to reduce boilerplate in class initialization by automatically generating attribute-setting behavior from the __init__ signature. For instance, the AutoInit metaclass wraps a class's __init__ method to set instance attributes directly from positional and keyword arguments, eliminating the need for manual assignments like self.make = make.[22]
from functools import wraps
from inspect import signature
def binds(f):
@wraps(f)
def __init__(self, *args, **kwargs):
vars(self).update([signature](/page/Signature)(f).bind(None, *args, **kwargs).arguments)
del self.self # Remove the 'self' binding added by [bind](/page/BIND)
return __init__
class AutoInit(type):
def __new__(cls, name, bases, [namespace](/page/Namespace)):
if '__init__' in [namespace](/page/Namespace):
[namespace](/page/Namespace)['__init__'] = binds([namespace](/page/Namespace)['__init__'])
return type.__new__(cls, name, bases, [namespace](/page/Namespace))
class AttributeInitType(AutoInit):
"""Custom metaclass for automatic attribute initialization."""
pass
class Car(metaclass=AttributeInitType):
def __init__(self, make, model, year):
"""Initializer with no manual attribute assignments needed."""
pass
# Usage
my_car = Car('Toyota', 'Corolla', 2023)
print(my_car.make) # Output: Toyota
print(my_car.model) # Output: Corolla
print(my_car.year) # Output: 2023
from functools import wraps
from inspect import signature
def binds(f):
@wraps(f)
def __init__(self, *args, **kwargs):
vars(self).update([signature](/page/Signature)(f).bind(None, *args, **kwargs).arguments)
del self.self # Remove the 'self' binding added by [bind](/page/BIND)
return __init__
class AutoInit(type):
def __new__(cls, name, bases, [namespace](/page/Namespace)):
if '__init__' in [namespace](/page/Namespace):
[namespace](/page/Namespace)['__init__'] = binds([namespace](/page/Namespace)['__init__'])
return type.__new__(cls, name, bases, [namespace](/page/Namespace))
class AttributeInitType(AutoInit):
"""Custom metaclass for automatic attribute initialization."""
pass
class Car(metaclass=AttributeInitType):
def __init__(self, make, model, year):
"""Initializer with no manual attribute assignments needed."""
pass
# Usage
my_car = Car('Toyota', 'Corolla', 2023)
print(my_car.make) # Output: Toyota
print(my_car.model) # Output: Corolla
print(my_car.year) # Output: 2023
__init__ signature for documentation and validation.[22]
For advanced scenarios involving multiple inheritance, Python resolves metaclass conflicts by selecting the most derived metaclass from the base classes' metaclasses, ensuring a coherent hierarchy through subtype checks; if no single metaclass is compatible (i.e., none is a subclass of all others), a TypeError is raised to prevent ambiguous behavior.[8] This resolution mechanism maintains consistency in the class's metaclass while allowing flexible inheritance patterns, as defined in PEP 3115, which standardized metaclass protocols in Python 3.[23]
In Ruby
In Ruby, metaclasses are implemented through a mechanism known as eigenclasses, also referred to as singleton classes, which provide a lightweight way to attach instance-specific methods to any object without affecting its class or other instances.[24] An eigenclass is an anonymous subclass of the object's class, created on demand when singleton methods are defined, and it serves as the immediate superclass in the method lookup chain for that object.[24] This design emphasizes Ruby's dynamic nature, allowing runtime modifications that are isolated to individual objects or classes. The primary syntax for accessing and defining an eigenclass isclass << obj, which opens the eigenclass of the specified object obj and allows method definitions within it. For example, to add a singleton method to an instance:
o = Object.new
class << o
def greet
"Hello from singleton!"
end
end
o.greet # => "Hello from singleton!"
o = Object.new
class << o
def greet
"Hello from singleton!"
end
end
o.greet # => "Hello from singleton!"
greet becomes available only on o, not on other instances of Object.[24] For classes themselves, which are objects inheriting from Class, the eigenclass is accessed using class << self within the class definition, enabling per-class methods (often called class methods) without relying on inheritance from a full metaclass hierarchy. An example is:
class Car
class << self
def factory
"Building a new car"
end
end
end
Car.factory # => "Building a new car"
class Car
class << self
def factory
"Building a new car"
end
end
end
Car.factory # => "Building a new car"
Car without subclassing or altering Class.[24]
Ruby's eigenclass system simplifies the metaclass hierarchies found in languages like Smalltalk, avoiding explicit metaclass classes and cycles in inheritance while maintaining a clean, one-to-one mapping where every eigenclass is an instance of Class.[19] In Smalltalk-80, metaclasses form a complex pseudotree with a dedicated Metaclass class as the root, leading to potential inheritance paradoxes and multiple roots; Ruby resolves this by using implicit, object-attached eigenclasses that integrate seamlessly into the single inheritance chain rooted at BasicObject.[19] The following table illustrates the key structural differences:
| Aspect | Smalltalk-80 Metaclasses | Ruby Eigenclasses |
|---|---|---|
| Hierarchy Structure | Pseudotree with explicit Metaclass root; potential cycles and multiple roots | Linear chain; all eigenclasses subclass Class; acyclic and single-rooted at BasicObject |
| Class Mapping | Metaclasses map to Metaclass via .rclass | All eigenclasses map to Class via .class |
| Creation | Explicit subclasses for each class | Implicit, anonymous on demand for any object |
| Inheritance Behavior | Broken in some implementations (e.g., Pharo, Squeak) | Consistent, with eigenclass as immediate superclass in lookup |
[String](/page/String) behavior for specific needs in a project.[24] They also power domain-specific languages (DSLs) by defining class-level methods that configure behavior, like in Rails routing or testing frameworks. To mitigate the risks of global monkey patching—such as unintended side effects across an application—Ruby 2.0 introduced refinements, which allow scoped extensions via modules that refine classes locally without permanent changes.[25] A refinement is defined using Module#refine and activated with using, limiting modifications to the lexical scope:
module StringRefinement
refine String do
def shout
upcase + "!"
end
end
end
using StringRefinement
"Hello".shout # => "HELLO!"
# Outside scope, "Hello".shout raises NoMethodError
module StringRefinement
refine String do
def shout
upcase + "!"
end
end
end
using StringRefinement
"Hello".shout # => "HELLO!"
# Outside scope, "Hello".shout raises NoMethodError
In Objective-C
In Objective-C, metaclasses form an integral part of the runtime system, where each class is paired with a corresponding metaclass that serves as the class of the class object itself. This pairing ensures that class objects, which represent the blueprint for creating instances, are treated as objects in their own right and can respond to messages. For instance, if a class namedCar inherits from Vehicle, which in turn inherits from NSObject, the metaclass of Car inherits from the metaclass of Vehicle, ultimately rooting in the metaclass of NSObject. This parallel inheritance hierarchy allows metaclasses to define and store class methods, enabling dynamic behavior for classes as objects.[26][27]
Metaclasses in Objective-C are implicit and do not have explicit names in source code; they are generated by the compiler and runtime during class definition. Access to a metaclass is achieved by sending the class message to a class object, such as [Car class], which returns the metaclass instance for Car. For dynamic introspection at runtime, functions like NSClassFromString and objc_getClass retrieve a class object by name from a string (e.g., Class carClass = NSClassFromString(@"Car");), after which the metaclass can be obtained via [carClass class]. These mechanisms support runtime queries and modifications, including checking if an object is a metaclass using class_isMetaClass. Additionally, objc_getMetaClass directly returns the metaclass for a given class name.[27][28]
A key application of metaclasses is runtime introspection and modification, exemplified by method swizzling, which exchanges implementations of class or instance methods dynamically. This is facilitated by runtime functions like method_exchangeImplementations, allowing developers to alter behavior without subclassing, often used in debugging or aspect-oriented programming. Metaclasses also handle class initialization through the +initialize method, a class method invoked automatically once per class (on its metaclass) before any other class or instance methods are called. For example:
+ (void)initialize {
if (self == [MyClass class]) {
// Perform one-time setup for the class, such as registering defaults.
}
}
+ (void)initialize {
if (self == [MyClass class]) {
// Perform one-time setup for the class, such as registering defaults.
}
}
Proposals and Support in Static Languages
C++ Metaclass Proposals
In 2017, Herb Sutter proposed metaclasses as a new language feature for C++ to enable more powerful compile-time code generation and abstraction, allowing users to define custom class categories with built-in behaviors such as automatic interface enforcement or value semantics.[30] This initial paper, P0707R0, introduced two primary metaclass types: interface metaclasses, which generate abstract base classes with pure virtual public functions and prohibit data members or copy/move operations to mimic Java or C# interfaces; and value metaclasses, which automatically provide default constructors, copy/move semantics, and equality comparisons for regular types like pairs or strings.[30] The motivation was to reduce boilerplate in library design, such as implementing a standard interface metaclass in just 10 lines versus the extensive specifications required in other languages, while adhering to C++'s zero-overhead principle through compile-time expansion.[30] The proposed syntax in P0707R0 used a declarative style with special keywords, exemplified by defining an interface metaclass as$class interface { public: $virtual ~interface() = default; template<class T> bool isa(); }; and applying it via interface Shape { int area(); };, which expands at compile time into a full abstract class with virtual destructor and the specified pure virtual function.[30] Similarly, a value metaclass could be defined to generate types with canonical behaviors, such as value Pair { T first; U second; }; producing a class with defaulted special member functions and operator==.[30] These metaclasses were intended to complement emerging features like concepts, enabling library authors to create extensible type systems without relying solely on templates or macros.[30] A prototype implementation was demonstrated using a modified Clang compiler, showcasing generative capabilities for patterns like observer or singleton.[30]
The metaclass proposal was not adopted for C++20 or C++23, as the standards committee prioritized foundational features including concepts for template constraints in C++20 and modules for better encapsulation in both standards, deferring advanced metaprogramming enhancements. Subsequent revisions of P0707, such as R3 in 2018 and R4 in 2019, refined the idea by assuming support for static reflection (e.g., via P0578) and compile-time programming (e.g., via P0633), shifting focus toward "metaclass functions" as consteval templates that generate code.[21][31]
In the 2020s, the proposal evolved further, with P0707R5 in October 2024 presenting metaclasses as syntactic sugar atop reflection facilities like P2996 (static reflection) and P3294 (code injection), using concise notation such as class(metafunc) Widget { /* declarations */ }; to invoke a consteval metafunction for class generation.[32] This version supports multiple metafunctions per class (e.g., class(xxx, yyy) Widget { ... };) and leverages tools like cppfront for full compiler support across MSVC, GCC, and Clang, emphasizing declarative authoring with automatic defaults and constraints.[32] While the core metaclass concept has transitioned from a standalone language primitive to a library-friendly extension of reflection—though it was not included in C++26 following the feature freeze, it remains under active development for potential inclusion in future standards without adoption in prior standards.[33]
Reflection Mechanisms as Alternatives
In static languages lacking native metaclass support, reflection mechanisms provide partial alternatives by enabling introspection and limited manipulation of types at compile-time or runtime, though they fall short of the full dynamic class modification offered by metaclasses. These approaches allow developers to query and interact with class metadata without altering the core language's static typing model.[34] The C++26 standard includes compile-time reflection through proposal P2996, which provides thestd::meta::info type and the ^^ reflection operator for accessing type information and object properties during compilation (adopted June 2025).[35] This facility supports operations like enumerating members of a type or substituting values into templates, serving as a foundation for metaprogramming tasks such as automatic serialization or trait generation, but it does not enable runtime class alterations or true metaclass inheritance.[35]
In Java, the Class<T> class acts as a reified representation of types, facilitating runtime introspection via methods like Class.forName() to load classes dynamically and access their fields, methods, and constructors through the java.lang.reflect package. This API supports tasks such as dependency injection and plugin systems by allowing code to examine and invoke members reflectively, yet it cannot create or modify classes on the fly, restricting it to observation and invocation rather than generative metaprogramming.[36]
Other languages extend reflection further toward metaclass-like capabilities. Similarly, Scala's implicits (now givens in Scala 3) provide partial substitutes via type classes, which attach behavior to types ad-hoc without subclassing, supporting polymorphic extensions that mimic some metaclass functionalities like implicit conversions and method resolution.
Despite these advancements, reflection mechanisms in static languages inherently limit dynamic class modification due to type safety and performance constraints, often requiring boilerplate code or external tools for anything approaching the seamless extensibility of true metaclasses, as seen in their inability to support open recursion or incremental protocol extensions without recompilation.[34]
Applications and Uses
Metaprogramming and Code Generation
Metaclasses facilitate metaprogramming by allowing programmers to intercept and customize the process of class creation, enabling dynamic modifications to class definitions at runtime or compile time. In this approach, a metaclass overrides methods like__new__ or equivalent hooks to inspect, alter, or generate class attributes and methods before the class is finalized. For instance, during class instantiation, the metaclass can validate the structure of the class body, ensuring required attributes are present or enforcing specific design constraints.[8][23]
One key technique involves injecting methods or attributes into the class namespace to automate common behaviors, such as automatically generating accessor methods or validation logic based on declarative annotations. This is particularly useful in scenarios like object-relational mapping, where a metaclass can analyze class fields and produce corresponding database interaction code, such as SQL queries, without explicit implementation in the class itself. Similarly, metaclasses can enforce design patterns by overriding creation mechanisms; for example, to implement a singleton pattern, the metaclass modifies the class's constructor to return a single instance, preventing multiple instantiations.[37][38]
Metaclasses also support code generation for declarative programming paradigms, where high-level descriptions expand into boilerplate code. By preparing a custom namespace during class body evaluation—via hooks like __prepare__—the metaclass can track declaration order, resolve forward references, or dynamically synthesize methods from simple declarations, transforming concise API definitions into fully functional implementations. In languages like Python, this mechanism enhances expressiveness by allowing classes to be defined declaratively while the metaclass handles expansion.[23][39]
Another abstract example is adding cross-cutting concerns, such as logging, where the metaclass scans the class for methods and injects wrapper functions that log calls without altering the original code. This interception reduces manual repetition, as developers declare intent once, and the metaclass propagates the behavior across the class hierarchy. Overall, these capabilities promote reusable metaprogramming abstractions, minimizing boilerplate and fostering domain-specific languages by centralizing customization logic at the metalevel.[8][40]
Frameworks, Libraries, and Tools
In web development frameworks, metaclasses play a crucial role in automating object-relational mapping (ORM) for database interactions. In Django, theModelBase metaclass is employed during model class creation to configure database table names, process field definitions, and establish relationships, enabling seamless integration with the ORM system.[41] Similarly, SQLAlchemy's declarative base relies on the DeclarativeMeta metaclass to intercept attribute assignments, such as mapped_column() calls, and dynamically append them to underlying Table and Mapper objects for runtime schema configuration.[42] Ruby on Rails' ActiveRecord framework leverages Ruby's metaclass (eigenclass) mechanisms through metaprogramming techniques like macro-style association declarations (e.g., has_many), which dynamically inject methods into model classes to handle database persistence without explicit boilerplate.[43]
Among libraries, Python's abc module utilizes the ABCMeta metaclass to enforce abstract base classes (ABCs), allowing developers to define interfaces with abstract methods via the @abstractmethod decorator and register virtual subclasses for type checking and polymorphism.[44] This metaclass enables runtime verification that concrete subclasses implement required methods, promoting robust code design in object-oriented hierarchies.
In modeling tools, metaclasses underpin formal languages for metadata representation. The Meta Object Facility (MOF), standardized by the Object Management Group (OMG), defines the Class metaclass within its Essential MOF (EMOF) and Complete MOF (CMOF) layers, reusing UML 2.5 constructs to model classes with properties, operations, and associations while enforcing constraints like singleton instances for metamodel elements.[45] Analogously, in the Resource Description Framework (RDF) Schema, rdfs:Class serves as a metaclass by classifying resources that are themselves RDF classes, supporting subclass hierarchies via rdfs:subClassOf and instance typing with rdf:type to enable extensible semantic modeling.[46]