Covariant Return Types in MathCore/MathMore

I am curious to know why root doesn’t make use of covariant return types in the MathCore/More libraries.

This causes a small issue when implementing a class that depends on an object derived from the ROOT::Math::IParametricFunctionMultiDim abstract base class. This was discovered because I need to store a smart pointer to a ROOT::Math::IParametricFunctionMultiDim type. It MUST be derived from this base class and not ROOT::Math::IBaseFunctionMultiDim because my class requires the function to be parametrized. However, when I tried to Clone my function to initialize my smart_ptr like this…

struct A 
{
     private: 
        boost::shared_ptr<ROOT::Math::IParametricFunctionMultiDim> fFunc;
     public:
         A( const ROOT::Math::IParametricFunctionMultiDim& func) : fFunc(func.Clone()) { /* ... */}

    /* the rest of the class */
};

This generates error messages like such…
/usr/include/boost/smart_ptr/shared_ptr.hpp:187:50: error: invalid conversion from ‘ROOT::Math::IBaseFunctionMultiDim*’ to ‘ROOT::Math::IParametricFunctionMultiDim*’ [-fpermissive]

This is simply b/c the smart_ptr believes me when I tell it that I am giving it the more derived type and makes no attempt to upcast it (it is just a template). I can write a bandaid by upcasting it myself but there really isn’t a reason to do so because C++ supports the ability of virtual functions to return objects of more derived types.

To improve this, I can add the pure virtual Clone method that returns a ROOT::Math::IParametricFunctionMultiDim pointer to its class, which I think makes sense b/c some people will want to treat this as the base class rather than the IBaseFunctionMultiDim (like me :smiley:).

namespace ROOT {
namespace Math {
class IParametricFunctionMultiDim 
{
  /*
    * current class definition 
    */
 
public:
  virtual IParametricFunctionMultiDim* Clone() const = 0;
};

} // end namespace Math
} // end namespace ROOT

This makes my code compile, however, it causes some of the other more derived classes of the MathMore libraries, such as
ROOT::Math::MultiDimParamGradFunctionAdapter, to complain.

include/Math/MultiDimParamFunctionAdapter.h:115:23: error: invalid covariant return type for ‘virtual ROOT::Math::MultiDimParamFunctionAdapter::BaseFunc* ROOT::Math::MultiDimParamFunctionAdapter::Clone() const’
include/Math/IParamFunction.h:115:41: error:   overriding ‘virtual ROOT::Math::IParametricFunctionMultiDim* ROOT::Math::IParametricFunctionMultiDim::Clone() const’

which occurs b/c these classes’ virtual Clone methods return pointers to one of the two ultimate base classes, ROOT::Math::IBaseFunctionMultiDim, rather than the ROOT::Math::IParametricFunctionMultiDim (or better yet themselves). The meaning of returning this type is nonsensical b/c they inherit from two abstract base classes rather than just one as the code implies.

Is it possible to make all of the mathmore/mathcore (and the rest of ROOT if applicable), do one of two things

  1. Utilize covariant return types by making all classes return a pointer of their own type from their inherited Clone method themselves. I think this is an optimal improvement from an understandability point of view and should be transparent to implement. There is a nice article about this topic here http://www.lwithers.me.uk/articles/covariant.html.

  2. If item 1 is not implemented, then make the more derived objects of ROOT::Math::IParametricFunctionMultiDim to return pointers to ROOT::Math::IParametricFunctionMultiDim rather than ROOT::Math::IBaseFunctionMultiDim from their Clone methods.

Thanks,
Jeromy