<commit_before>#ifndef tut_polymorphism_hpp
#define tut_polymorphism_hpp

#include <cstddef>
#include <functional>

namespace tut
{
    // This tutorial gives an overview of the data abstraction-style in C++ (DAS).
    //
    // DAS is a simple, powerful, composable, and efficient style of C++ programming. It is the
    // combination of four major implementation techniques -
    //
    // 1) data abstractions rather than OOP objects
    // 2) stand-alone functions rather than member functions
    // 3) opaque mixins rather than OOP inheritance
    // 4) the following types of polymorphism rather than OOP polymorphism -
    //      a) ad-hoc polymorphism (function overloading)
    //      b) structural polymorphism (function templates without specialization)
    //      c) static polymorphisms (function template with specialization)
    //
    // Subtype polymorphism should be used only when necessary, such as in mixins and plugins.
    // 
    // In these tutorial and with the library code provided in this repository, I hope to
    // demonstrate the outright superiority of DAS programming in C++ over its alternatives.
    //
    // So let's get started!

    // Here we have a data abstraction, or 'DA'. You can tell it is different from an OOP object as
    // it has no public functions (save for ctors, dtors, and operators). Its advantages are that
    // it should keep you from using OOP unnecessarily, and has better generic usage (especially
    // with respect to the following forms of polymorphism).
    //
    // Also unlike objects, DA's only do what they must in order to implement a localized
    // semantics, rather than as much as they can for the wider system.
    //
    // For example, if you have a simulant DA in a simulation, it won't be that simulant's role to
    // hold on to a shader and texture handle to render itself. Instead, the DA will be a bag of
    // data properties with invariants that preseve consistency. To perform sepcialized tasks like
    // rendering or physics, the simulant DA sends data messages that describe the desired
    // rendering or physics results to a renderer or physics system. It is up to these
    // specialized systems to manage resources and perform the tasks that the data messages
    // describe.
    //
    // The downside to DAs is that they are considered novel in some C++ shops, and their adoption
    // may therefore pose political difficulties.
    class data_abstraction
    {
    private:

        // A private field. Note that having a single, const private field is rarely a good enough
        // reason to use a DA, but we're just giving a toy example to keeps things simple.
        const int value;

    protected:

        // Here we have a friend declaration that allows us to implement our interface. I make
        // protected because that seems to appease the ordering in more involved types, but you
        // can make them private if your prefer.
        friend int func(const data_abstraction&);

    public:

        // A public constructor that initializes the private value.
        data_abstraction(int value) : value(value) { }
    };

    // Here we write forwarding functions for our DA's functions. Exposing the interface like
    // this will provide us the additional genericity that is accompanied by ad-hoc polymorphism
    // (AKA, operator-overloading). Stand-alone functions are considered preferable to member
    // functions for many reasons. See http://www.gotw.ca/gotw/084.htm and
    // http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197
    int func(const data_abstraction& da)
    {
        return da.value * 5;
    }

    // Unlike with OOP in C++, extending a DA is easy; just add a function in the same namesapce
    // as the DA, and you're done! Look ma, no inheritance!
    int extension(const data_abstraction& da)
    {
        return func(da) + 5;
    }

    // Structural, or 'static duck-type', polymorphism is easy, useful, and usually politically
    // viable in C++ shops. However, it's not the most powerful form of static polymorphism in
    // C++, and its applicability is therefore limited.
    template<typename T>
    int pow(const T& t)
    {
        return func(t) * func(t);
    }

    // An extended pow function.
    template<typename T>
    int pow_ex(const T& t)
    {
        return extension(t) * extension(t);<commit_msg>Update polymorphism.hpp<commit_after>#ifndef tut_polymorphism_hpp
#define tut_polymorphism_hpp

#include <cstddef>
#include <functional>

namespace tut
{
    // This tutorial gives an overview of the data abstraction-style in C++ (DAS).
    //
    // DAS is a simple, powerful, composable, and efficient style of C++ programming. It is the
    // combination of four major implementation techniques -
    //
    // 1) data abstractions rather than OOP objects
    // 2) stand-alone functions rather than member functions
    // 3) opaque mixins rather than OOP inheritance
    // 4) the following types of polymorphism rather than OOP polymorphism -
    //      a) ad-hoc polymorphism (function overloading)
    //      b) structural polymorphism (function templates without specialization)
    //      c) static polymorphisms (function template with specialization)
    //
    // Subtype polymorphism should be used only when necessary, such as in mixins and plugins.
    // 
    // In these tutorial and with the library code provided in this repository, I hope to
    // demonstrate the outright superiority of DAS programming in C++ over its alternatives.
    //
    // So let's get started!

    // Here we have a data abstraction, or 'DA'. You can tell it is different from an OOP object as
    // it has no public functions (save for ctors, dtors, and operators). Its has better generic
    // usage (especially with respect to the above preferred forms of polymorphism) and exposes a
    // much simpler and more extensible interface. Adding a new functions to DAs is as easy as
    // opening up its containing namespace and plopping on in, as opposed to using inheritance to
    // add a new object member function.
    //
    // Also unlike objects, DA's only do what they must in order to implement a localized
    // semantics, rather than as much as they can for the wider system.
    //
    // For example, if you have a simulant DA in a simulation, it won't be that simulant's role to
    // hold on to a shader and texture handle to render itself. Instead, the DA will be a bag of
    // data properties with invariants that preseve consistency. To perform sepcialized tasks like
    // rendering or physics, the simulant DA sends data messages that describe the desired
    // rendering or physics results to a renderer or physics system. It is up to these
    // specialized systems to manage resources and perform the tasks that the data messages
    // describe.
    //
    // The downside to DAs is that they are considered novel in some C++ shops, and may therfore
    // pose adoption difficulties in practice.
    class data_abstraction
    {
    private:

        // A private field. Note that having a single, const private field is rarely a good enough
        // reason to use a DA, but we're just giving a toy example to keeps things simple.
        const int value;

    protected:

        // Here we have a friend declaration that allows us to implement our interface. I make
        // protected because that seems to appease the ordering in more involved types, but you
        // can make them private if your prefer.
        friend int func(const data_abstraction&);

    public:

        // A public constructor that initializes the private value.
        data_abstraction(int value) : value(value) { }
    };

    // Here we expose our DA's interface with stand-alone functions. For more on why Stand-alone
    // functions are considered strictly superior to OO-style member functions, see -
    // http://www.gotw.ca/gotw/084.htm and -
    // http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197
    int func(const data_abstraction& da)
    {
        return da.value * 5;
    }

    // Unlike with OO interfaces, extending a DA is easy; even if you're in a different file or
    // code base, just open up the DA's namespace and add functions to you heart's content!
    int extension(const data_abstraction& da)
    {
        return func(da) + 5;
    }

    // Structural, or 'static duck-type', polymorphism is easy, useful, and usually politically
    // viable in C++ shops. However, it's not the most powerful form of static polymorphism in
    // C++, and its applicability is therefore limited.
    template<typename T>
    int pow(const T& t)
    {
        return func(t) * func(t);
    }

    // An extended pow function.
    template<typename T>
    int pow_ex(const T& t)
    {
        return extension(t) * extension(t);
{'fraction_non_alphanumeric': 0.0704114811077475, 'fraction_numerical': 0.004036326942482341, 'mean_word_length': 2.676834295136026, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4485064', 'n_tokens_mistral': 2419, 'n_tokens_neox': 2226, 'n_words': 1147}