.. _omnigraph_versioning_carbonite:

OmniGraph Versioning For Carbonite Interfaces
#############################################

See the description of the :ref:`omnigraph_carbonite_versions`.

For this example this sample interface will be used, shown in its initial form. Note the structure integrity check at
the end, designed to catch situations where a new function is unintentionally added to the middle of the interface.

.. code-block:: cpp

    class ITestInterface
    {
        CARB_PLUGIN_INTERFACE("omni::graph::core::ITestInterface", 1, 0);

        /**
         * Does the old thing
         *
         * @param[in] value The value of the old thing
         */
        void (CARB_ABI* oldFunction)(int value);
    };
    // Update this every time a new ABI function is added, to ensure one isn't accidentally added in the middle
    STRUCT_INTEGRITY_CHECK(IAttribute, oldFunction, 1)

    void oldFunction_impl(int value)
    {
        doSomething(value);
        return;
    }

Adding A Function
*****************

A new function is added. The version number is bumped and the structural integrity check is updated.

.. code-block:: cpp
    :emphasize-lines: 3,12-17,20,28-32

    class ITestInterface
    {
        CARB_PLUGIN_INTERFACE("omni::graph::core::ITestInterface", 1, 1);

        /**
         * Does the old thing
         *
         * @param[in] value The value of the old thing
         */
        void (CARB_ABI* oldFunction)(int value);

        /**
         * Does the new thing
         *
         * @param[in] value The value of the new thing
         */
        void (CARB_ABI* newFunction)(int value);
    };
    // Update this every time a new ABI function is added, to ensure one isn't accidentally added in the middle
    STRUCT_INTEGRITY_CHECK(IAttribute, newFunction, 2)

    void oldFunction_impl(int value)
    {
        doSomething(value);
        return;
    }

    void newFunction_impl(int value)
    {
        doSomethingNew(value);
        return;
    }


Deprecating Functions
*********************

In the rare occasion where you want to deprecate a function entirely you must follow this three-step process to
ensure maximum compatibility and notification to affected users.

Step 1: Add a Deprecation Notice
================================

The team should decide exactly when a deprecation will happen, as it is beneficial to group deprecations together to
minimize the work required on the user end to deal with the deprecations. Once that's decided the first thing to do is
to communicate the deprecation intent through the decided-upon channels.

Once that has happend the implementation of the interface function will add a warning message that the function is
deprecated and will be going away.

.. code-block:: cpp
    :emphasize-lines: 6,26

    class ITestInterface
    {
        CARB_PLUGIN_INTERFACE("omni::graph::core::ITestInterface", 1, 1);

        /**
         * This function is deprecated - use newFunction() instead
         *
         * Does the old thing
         *
         * @param[in] value The value of the old thing
         */
        void (CARB_ABI* oldFunction)(int value);

        /**
         * Does the new thing
         *
         * @param[in] value The value of the new thing
         */
        void (CARB_ABI* newFunction)(int value);
    };
    // Update this every time a new ABI function is added, to ensure one isn't accidentally added in the middle
    STRUCT_INTEGRITY_CHECK(IAttribute, newFunction, 2)

    void oldFunction_impl(int value)
    {
        CARB_LOG_WARNING("ITestInterface::oldFunction() is deprecated - use ITestInterface::newFunction() instead");
        doSomething(value);
        return;
    }

    void newFunction_impl(int value)
    {
        doSomethingNew(value);
        return;
    }

Step 2: Make The Deprecated Path An Error
=========================================

To ensure the use of the deprecated path is highly visible in this phase the warning is upgraded to an error and the
comments on the function make it more clear that it is not to be used in new code.

.. code-block:: cpp
    :emphasize-lines: 6-7,22

    class ITestInterface
    {
        CARB_PLUGIN_INTERFACE("omni::graph::core::ITestInterface", 1, 1);

        /**
         * This function is deprecated - use newFunction() instead
         */
        void (CARB_ABI* oldFunction)(int value);

        /**
         * Does the new thing
         *
         * @param[in] value The value of the new thing
         */
        void (CARB_ABI* newFunction)(int value);
    };
    // Update this every time a new ABI function is added, to ensure one isn't accidentally added in the middle
    STRUCT_INTEGRITY_CHECK(IAttribute, newFunction, 2)

    void oldFunction_impl(int value)
    {
        CARB_LOG_ERROR("ITestInterface::oldFunction() is deprecated - use ITestInterface::newFunction() instead");
        doSomething(value);
        return;
    }

    void newFunction_impl(int value)
    {
        doSomethingNew(value);
        return;
    }

Step 3: Hard Deprecation Of The Function
========================================

To ensure the ABI integrity functions may not be removed from the interface, however they can be renamed and all
information about what they once were can be removed. At this point calls to them will no longer function. They will
only issue an error. The function signatures remain the same to avoid type errors. The implementation of the deprecated
function can be moved to a common graveyard of deprecated functions.

.. code-block:: cpp
    :emphasize-lines: 5,23-27

    class ITestInterface
    {
        CARB_PLUGIN_INTERFACE("omni::graph::core::ITestInterface", 1, 1);

        /* DEPRECATED */ void (CARB_ABI* deprecated_1)(int);

        /**
         * Does the new thing
         *
         * @param[in] value The value of the new thing
         */
        void (CARB_ABI* newFunction)(int value);
    };
    // Update this every time a new ABI function is added, to ensure one isn't accidentally added in the middle
    STRUCT_INTEGRITY_CHECK(IAttribute, newFunction, 2)

    void newFunction_impl(int value)
    {
        doSomethingNew(value);
        return;
    }

    void oldFunction_impl(int)
    {
        CARB_LOG_ERROR("ITestInterface::oldFunction() is deprecated - use ITestInterface::newFunction() instead");
        return;
    }

