diff --git a/doc/doxygen/DoxygenDumuxLayout.xml b/doc/doxygen/DoxygenDumuxLayout.xml index b2d2c6de4f878e8589505041cca87624a0d13335..dc5de16a0726139faf992682f1ad161154a11c84 100644 --- a/doc/doxygen/DoxygenDumuxLayout.xml +++ b/doc/doxygen/DoxygenDumuxLayout.xml @@ -33,6 +33,7 @@ SPDX-License-Identifier: GPL-3.0-or-later <tab type="user" url="@ref dumux-and-dune" visible="yes" title="Dumux and Dune" intro=""/> <tab type="user" url="@ref developing-dumux" visible="yes" title="Developing Dumux" intro=""/> <tab type="user" url="@ref building-the-documentation" visible="yes" title="Build doxygen documentation" intro=""/> + <tab type="user" url="@ref changing-property-name" visible="yes" title="Changing property name" intro=""/> </tab> <tab type="user" url="@ref citelist" visible="yes" title="Bibliography" intro=""/> <tab type="namespaces" visible="yes" title=""> diff --git a/doc/doxygen/pages/changing-property-name.md b/doc/doxygen/pages/changing-property-name.md new file mode 100644 index 0000000000000000000000000000000000000000..673a2e64bf64c0eb9457c26e98a1fd72afd5b356 --- /dev/null +++ b/doc/doxygen/pages/changing-property-name.md @@ -0,0 +1,181 @@ +# 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 `dumux` before release + +#### Deprecate the old property + +```c++ +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 + +```c++ +#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 + +```c++ +#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 +```c++ +using MyOldFavoriteName = GetPropType<TypeTag, Properties::OldProperty>; +``` +to +```c++ +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: +```c++ +public: + using OldProperty = GetPropType<TypeTag, Properties::OldProperty>; +``` +should become +```c++ +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 +```c++ +using MyOldFavoriteName = GetPropType<TypeTag, Properties::OldProperty>; +``` +to +```c++ +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 +```c++ +struct OldProperty<TypeTag, TTag::SpecialModel> { + using type = SpecialType<...>; +}; +``` +to +```c++ +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 `dumux` after release + +#### Only define the new property + +Replace the two snippets "Deprecate the old property" and "Define the new property" by +```c++ +template<class TypeTag, class MyTypeTag> +struct NewProperty { using type = UndefinedProperty; }; +``` + +#### Only specialize the new property + +Replace the dumux code base snippet "Treat specializations" by +```c++ +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 +```c++ + using LastType = Property<TypeTag, LastTypeTag>; +``` +in `GetDefined` in `dumux/common/properties/propertysystem.hh` has to be augmented to +```c++ +#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 +```c++ + using FirstType = Property<TypeTag, FirstTypeTag>; +``` +and +```c++ +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; } +``` +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`: +```c++ +#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 +```