You can edit almost every page by Creating an account and confirming your email.

YOMM2

From EverybodyWiki Bios & Wiki



This user has made a public declaration indicating that they have a conflict of interest with regard to the following Wikipedia article(s):
YOMM2
Developer(s)Jean-Louis Leroy
Stable release
1.3.1 / January 9, 2023; 3 years ago (2023-01-09)
Written inC++17
Engine
    Operating systemCross-platform
    TypeLanguage extensions
    LicenseBoost Software License
    Websitehttps://github.com/jll63/yomm2

    Search YOMM2 on Amazon.

    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

    The 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

    // =============================================================================
    // 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

    The 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

    1. Pirkelbauer, Peter; Solodkyy, Yuryi; Stroustrup, Bjarne. "Open Multi-Methods for C++" (PDF).

    External links


    This article "YOMM2" is from Wikipedia. The list of its authors can be seen in its historical and/or the page Edithistory:YOMM2. Articles copied from Draft Namespace on Wikipedia could be seen on the Draft Namespace of Wikipedia and not main one.