Submission declined on 27 June 2023 by Karnataka (talk). This submission is not adequately supported by reliable sources. Reliable sources are required so that information can be verified. If you need help with referencing, please see Referencing for beginners and Citing sources. This draft's references do not show that the subject qualifies for a Wikipedia article. In summary, the draft needs multiple published sources that are:
Where to get help
How to improve a draft
You can also browse Wikipedia:Featured articles and Wikipedia:Good articles to find examples of Wikipedia's best writing on topics similar to your proposed article. Improving your odds of a speedy review To improve your odds of a faster review, tag your draft with relevant WikiProject tags using the button below. This will let reviewers know a new draft has been submitted in their area of interest. For instance, if you wrote about a female astronomer, you would want to add the Biography, Astronomy, and Women scientists tags. Editor resources
|
- Comment: The only source is on the paper in which this is inspired by, nothing about the subject itself. Karnataka (talk) 21:55, 27 June 2023 (UTC)
This user has publicly declared that they have a conflict of interest regarding the Wikipedia article YOMM2. |
Developer(s) | Jean-Louis Leroy |
---|---|
Stable release | 1.3.1
/ January 9, 2023 |
Written in | C++17 |
Operating system | Cross-platform |
Type | Language extensions |
License | Boost Software License |
Website | https://github.com/jll63/yomm2 |
The YOMM2 library implements open multi-methods for C++17 and above.
Bjarne Stroustrup gave CLOS open multi-methods as an example of a feature from another language that he likes. He talks about them in Design and Evolution of C++, and suggests a syntax. Later, he and his students co-wrote a series of papers on the subject.
Overview
editThe declare_method macro declares a method. It is equivalent to defgeneric in the Common Lisp Object System. It takes a return type, a method name, and a list of types, some of which are marked as virtual (using the virtual_ decorator).
The define_method macro adds definitions, or specializations, to a previously declared method. It is equivalent to defgeneric in CLOS. It takes a return type, a method name, a parameter list, and is followed by a function body.
When a method is called, the dynamic types of the arguments corresponding to the virtual parameters of the method are used to select the appropriate definition to call, from the set of registered definitions. The selection is made according to the same rules as overload resolution, albeit it happens when the program is run, not compiled.
All classes potentially involved in a method call must be registered via the macro use_classes.
The yorel::yomm2::update_methods must be called before making calls to methods.
YOMM2 also provides a core interface, which does not use macros, and thus makes it possible to use the library in conjunction with templates.
Example
edit// =============================================================================
// Define a few polymorphic classes...
class Animal {
public:
virtual ~Animal() {
}
};
class Dog : public Animal {};
class Bulldog : public Dog {};
class Cat : public Animal {};
class Dolphin : public Animal {};
// =============================================================================
// Add behavior to existing classes, without modifying them.
#include <yorel/yomm2/keywords.hpp>
// Classes must be registered:
register_classes(Animal, Dog, Cat, Dolphin);
// ...but it does not have to be in one call to 'register_classes', as long as
// inheritance relationships can be deduced. This allows *adding* classes to an
// existing collection of classes.
register_classes(Dog, Bulldog);
// Define a uni-method, i.e. a method with a single virtual argument. This is in
// essence a virtual function implemented as a free function.
declare_method(void, kick, (virtual_<Animal&>, std::ostream&));
// Implement 'kick' for dogs.
define_method(void, kick, (Dog& dog, std::ostream& os)) {
os << "bark";
}
// Implement 'kick' for bulldogs. They behave like Dogs, but, in addition, they
// fight back.
define_method(void, kick, (Bulldog& dog, std::ostream& os)) {
next(dog, os); // calls "base" method, i.e. definition for Dog
os << " and bite";
}
// A multi-method with two virtual arguments...
declare_method(
void, meet, (virtual_<Animal&>, virtual_<Animal&>, std::ostream&));
// 'meet' catch-all implementation.
define_method(void, meet, (Animal&, Animal&, std::ostream& os)) {
os << "ignore";
}
// Add definitions for specific pairs of animals.
define_method(void, meet, (Dog& dog1, Dog& dog2, std::ostream& os)) {
os << "wag tail";
}
define_method(void, meet, (Dog& dog, Cat& cat, std::ostream& os)) {
os << "chase";
}
define_method(void, meet, (Cat& cat, Dog& dog, std::ostream& os)) {
os << "run";
}
// =============================================================================
// main
#include <iostream>
#include <memory>
int main() {
// Initialise method dispatch tables.
yorel::yomm2::update_methods();
// Create a few objects.
// Note that the actual classes are type-erased to base class Animal!
std::unique_ptr<Animal>
hector = std::make_unique<Bulldog>(),
snoopy = std::make_unique<Dog>(),
sylvester = std::make_unique<Cat>(),
flipper = std::make_unique<Dolphin>();
// Call 'kick'.
std::cout << "kick snoopy: ";
kick(*snoopy, std::cout); // bark
std::cout << "\n";
std::cout << "kick hector: ";
kick(*hector, std::cout); // bark and bite
std::cout << "\n";
// Call 'meet'.
std::cout << "hector meets sylvester: ";
meet(*hector, *sylvester, std::cout); // chase
std::cout << "\n";
std::cout << "sylvester meets hector: ";
meet(*sylvester, *hector, std::cout); // run
std::cout << "\n";
std::cout << "hector meets snoopy: ";
meet(*hector, *snoopy, std::cout); // wag tail
std::cout << "\n";
std::cout << "hector meets flipper: ";
meet(*hector, *flipper, std::cout); // ignore
std::cout << "\n";
}
Design
editThe library is inspired by the paper "Open Multi-Methods for C++", by Peter Pirkelbauer, Yuryi Solodkyy and Bjarne Stroustrup [1] .
At compilation time, YOMM2 uses macro and template meta-programming to collect information about classes, methods, and method definitions, and stores it in static objects.
At initialization time, YOMM2 calculates the inheritance relationships between the registered classes, and, for each method, which definition should be called for every possible tuple of virtual arguments. For each class, it builds a method table. For uni-methods, it contains a pointer to the applicable definition. For multi-methods, it contains a pointer to a multi-dimensional dispatch table, which is free of redundancies. YOMM2 also finds a perfect hash function for the typeid of the registered classes, and uses it to build a hash table that maps typeids to method tables.
At dispatch time, YOMM2 reads the dynamic typeid of the virtual arguments, and uses the hash table to retrieve the corresponding method tables. In release builds, a method call is very fast: calling a uni-method is almost as fast as calling an equivalent virtual function. In debug builds, YOMM2 performs various checks to detect and clearly report errors such as missing or ambiguous definitions, or missing class registrations.
References
edit- ^ Pirkelbauer, Peter; Solodkyy, Yuryi; Stroustrup, Bjarne. "Open Multi-Methods for C++" (PDF).
External links
edit
Category:Free software programmed in C++
Category:C++ libraries
Category:Articles with example C++ code