version 3.10-dev
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
Changing property name

Suppose that we want to change the name of the property OldProperty to NewProperty. In order to stay backwards compatible, a user should be able to use both the new name and the old name. If he uses the old name, he should get a deprecation warning, but his code should still do the same as before.

The only working possibility is to have two properties OldProperty and NewProperty and to set by default the new one to the old one. The other way around, a user could only invoke OldProperty in his using declarations if he doesn't specialize NewProperty in his own code.

Actions to be done in the module <tt>dumux</tt> before release

Deprecate the old property

template<class TypeTag, class MyTypeTag>
struct [[deprecated("Use OldProperty instead.")]] OldProperty { using type = UndefinedProperty; };

Properties are usually defined in dumux/common/properties.hh.

Define the new property

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
template<class TypeTag, class T>
struct NewPropertyHelper
{ using type = GetPropType<TypeTag, Properties::OldProperty>; };
template<class TypeTag>
struct NewPropertyHelper<TypeTag, UndefinedProperty>
{ using type = UndefinedProperty; };
template<class TypeTag, class MyTypeTag>
struct NewProperty
{
using type = typename NewPropertyHelper<TypeTag, typename OldProperty<TypeTag, MyTypeTag>::type>::type;
};
#pragma GCC diagnostic pop

The ignore pragmas avoid the emission of deprecation warnings for using the old property inside. The indirection via the helper class is required to allow specializing the new property with an undefined/unspecialized old one.

Treat specializations

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
struct OldProperty<TypeTag, TTag::SpecialModel> {
using type = SpecialType<...>;
};
#pragma GCC diagnostic pop

Specializations still have to be performed in terms of the old property, otherwise user code can't employ the old name. Only the ignore pragmas have to be added.

Use the new name

Change all

using MyOldFavoriteName = GetPropType<TypeTag, Properties::OldProperty>;

to

using MyNewFavoriteName = GetPropType<TypeTag, Properties::NewProperty>;

Export the new name

Very often, MyOldFavoriteName in the snippet above coincides with OldProperty. In this case, it is advisable to set MyNewFavoriteName to NewProperty. While this is unproblematic if the alias is local, take special care for exported names:

public:
using OldProperty = GetPropType<TypeTag, Properties::OldProperty>;

should become

public:
using NewProperty = GetPropType<TypeTag, Properties::NewProperty>;
using OldProperty [[deprecated("Use NewProperty instead.")]] = NewProperty;

Actions to be done in derived modules and user code

Change using declarations

Change all

using MyOldFavoriteName = GetPropType<TypeTag, Properties::OldProperty>;

to

using MyNewFavoriteName = GetPropType<TypeTag, Properties::NewProperty>;

If MyOldFavoriteName is exported and you care about backwards compatibility, consider deprecating it as outlined above.

Treat specializations

Change all

struct OldProperty<TypeTag, TTag::SpecialModel> {
using type = SpecialType<...>;
};

to

struct NewProperty<TypeTag, TTag::SpecialModel> {
using type = SpecialType<...>;
};

This should work because everywhere we now get the new property, so it is possible to overwrite it without breaking the code.

Actions to be done in the module <tt>dumux</tt> after release

Only define the new property

Replace the two snippets "Deprecate the old property" and "Define the new property" by

template<class TypeTag, class MyTypeTag>
struct NewProperty { using type = UndefinedProperty; };

Only specialize the new property

Replace the dumux code base snippet "Treat specializations" by

struct NewProperty<TypeTag, TTag::SpecialModel> {
using type = SpecialType<...>;
};

Remove exports of the old name

Remove the line containing the deprecation from the snippet "Export the new name".

Known limitation

Unfortunately, clang emits false positives when invoking the outlined strategy. A workaround is to prevent clang from emitting deprecation warnings triggered by using GetPropType and getPropValue(). To this end, the line

using LastType = Property<TypeTag, LastTypeTag>;

in GetDefined in dumux/common/properties/propertysystem.hh has to be augmented to

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
using LastType = Property<TypeTag, LastTypeTag>;
#ifdef __clang__
#pragma clang diagnostic pop
#endif

The lines

using FirstType = Property<TypeTag, FirstTypeTag>;

and

template<class TypeTag, template<class,class> class Property>
using GetPropType = typename Properties::Detail::GetPropImpl<TypeTag, Property>::type::type;
template<class TypeTag, template<class,class> class Property>
constexpr auto getPropValue() { return Properties::Detail::GetPropImpl<TypeTag, Property>::type::value; }
constexpr auto getPropValue()
get the value data member of a property
Definition: propertysystem.hh:310
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:296

have to be treated in the same way.

This should be augmented by a general warning message that is put best before the deprecation of the old property in dumux/common/properties.hh:

#if defined(__clang__) && !defined(DONT_EMIT_CLANG_NEWPROPERTY_WARNING)
#warning "The property `OldProperty` is deprecated in favor of `NewProperty` \
and will be removed after release X.Y. \
If clang is used, no deprecation warnings are emitted. \
We recommend to use gcc for getting rid of the warnings. \
You can suppress this message by defining the preprocessor variable \
DONT_EMIT_CLANG_NEWPROPERTY_WARNING."
#endif

🛠 Edit above doc on GitLab