Re: [boost] [type_traits][core] modularisation and moving stuff about (again)
Andrey Semashev wrote:
I would rather encourage people use type traits, the official interface. Boost.Config or Boost.TypeTraits could provide macros that allow users to detect whether is_final is emulated or is the real deal.
One thing about this suggestion: If Boost.Config was to provide macros that tell users whether Boost.TypeTraits' boost::is_final<T>::value is emulated or the real deal, then the compiler detection logic currently in Boost.TypeTraits for detecting __is_final would already have to be duplicated in Boost.Config. That does not sound like a great idea. Right now TypeTraits provides both, which is better. i.e. It provides boost::is_final<T>::value and BOOST_IS_FINAL(T). The former uses the latter if it is defined, or is always false if not defined. If BOOST_IS_FINAL(T) and all its compiler detection logic lives in TypeTraits, then that all that compiler detection logic should not be duplicated in Config to provide a BOOST_HAS_IS_FINAL_INTRINSIC or similar feature detection macro. Glen
On 23/08/2018 13:31, Glen Fernandes wrote:
One thing about this suggestion: If Boost.Config was to provide macros that tell users whether Boost.TypeTraits' boost::is_final<T>::value is emulated or the real deal, then the compiler detection logic currently in Boost.TypeTraits for detecting __is_final would already have to be duplicated in Boost.Config. That does not sound like a great idea.
Right now TypeTraits provides both, which is better. i.e. It provides boost::is_final<T>::value and BOOST_IS_FINAL(T). The former uses the latter if it is defined, or is always false if not defined.
If BOOST_IS_FINAL(T) and all its compiler detection logic lives in TypeTraits, then that all that compiler detection logic should not be duplicated in Config to provide a BOOST_HAS_IS_FINAL_INTRINSIC or similar feature detection macro.
What if Boost.Config contained all the compiler detection logic to define BOOST_HAS_IS_FINAL_INTRINSIC or not, and then Boost.TypeTraits had no detection and simply used BOOST_HAS_IS_FINAL_INTRINSIC to then define BOOST_IS_FINAL and boost::is_final<T> appropriately? That seems like a more appropriate division of responsibilities to me. (Unless I'm missing something about the implementation, which I haven't examined.) Although granted this doesn't solve Boost.Core wanting to use is_final, unless it's allowed to use TypeTraits, or unless it just wants BOOST_HAS_IS_FINAL_INTRINSIC and not the full trait.
On Wed, Aug 22, 2018 at 10:14 PM Gavin Lambert wrote:
What if Boost.Config contained all the compiler detection logic to define BOOST_HAS_IS_FINAL_INTRINSIC or not, and then Boost.TypeTraits had no detection and simply used BOOST_HAS_IS_FINAL_INTRINSIC to then define BOOST_IS_FINAL and boost::is_final<T> appropriately?
Boost.Config simply providing BOOST_HAS_IS_FINAL_INTRINSIC which is defined or not defined would mean Boost.TypeTraits would still need to do the compiler detection logic to map its BOOST_IS_FINAL(T) to the appropriate compiler intrinsic. e.g. For Sun it's __oracle_is_final(T), for most others it's __is_final(T), for DMC it's (__typeinfo(T) & 0x1000). Ultimately, it is not so far from what I proposed to John and created pull requests for. Except instead of a macro named "BOOST_HAS_IS_FINAL_INTRINSIC" in Config which is defined or not-defined, the macro in Config is named "BOOST_IS_FINAL(T)" which is defined to the appropriate intrinsic, or not defined at all. TypeTraits will still provide boost::is_final which uses BOOST_IS_FINAL if defined, or is otherwise false. Except now BOOST_IS_FINAL lives in Config, and all the compiler-detection logic lives solely in Config.
That seems like a more appropriate division of responsibilities to me.
Agreed. I prefer as much compiler-detection to reside in Config where I feel it has the best maintenance. Glen
On 08/23/18 05:27, Glen Fernandes via Boost wrote:
On Wed, Aug 22, 2018 at 10:14 PM Gavin Lambert wrote:
What if Boost.Config contained all the compiler detection logic to define BOOST_HAS_IS_FINAL_INTRINSIC or not, and then Boost.TypeTraits had no detection and simply used BOOST_HAS_IS_FINAL_INTRINSIC to then define BOOST_IS_FINAL and boost::is_final<T> appropriately?
Boost.Config simply providing BOOST_HAS_IS_FINAL_INTRINSIC which is defined or not defined would mean Boost.TypeTraits would still need to do the compiler detection logic to map its BOOST_IS_FINAL(T) to the appropriate compiler intrinsic. e.g. For Sun it's __oracle_is_final(T), for most others it's __is_final(T), for DMC it's (__typeinfo(T) & 0x1000).
Ultimately, it is not so far from what I proposed to John and created pull requests for. Except instead of a macro named "BOOST_HAS_IS_FINAL_INTRINSIC" in Config which is defined or not-defined, the macro in Config is named "BOOST_IS_FINAL(T)" which is defined to the appropriate intrinsic, or not defined at all.
TypeTraits will still provide boost::is_final which uses BOOST_IS_FINAL if defined, or is otherwise false. Except now BOOST_IS_FINAL lives in Config, and all the compiler-detection logic lives solely in Config.
What if the compiler intrinsic doesn't work in some cases? Boost.TypeTraits apply workarounds for such cases, so that the official trait works as intended. These workarounds might be impossible or expensive to do within a macro.
On Thursday, August 23, 2018, Andrey Semashev via Boost < boost@lists.boost.org> wrote:
On 08/23/18 05:27, Glen Fernandes via Boost wrote:
On Wed, Aug 22, 2018 at 10:14 PM Gavin Lambert wrote:
What if Boost.Config contained all the compiler detection logic to define BOOST_HAS_IS_FINAL_INTRINSIC or not, and then Boost.TypeTraits had no detection and simply used BOOST_HAS_IS_FINAL_INTRINSIC to then define BOOST_IS_FINAL and boost::is_final<T> appropriately?
Boost.Config simply providing BOOST_HAS_IS_FINAL_INTRINSIC which is defined or not defined would mean Boost.TypeTraits would still need to do the compiler detection logic to map its BOOST_IS_FINAL(T) to the appropriate compiler intrinsic. e.g. For Sun it's __oracle_is_final(T), for most others it's __is_final(T), for DMC it's (__typeinfo(T) & 0x1000).
Ultimately, it is not so far from what I proposed to John and created pull requests for. Except instead of a macro named "BOOST_HAS_IS_FINAL_INTRINSIC" in Config which is defined or not-defined, the macro in Config is named "BOOST_IS_FINAL(T)" which is defined to the appropriate intrinsic, or not defined at all.
TypeTraits will still provide boost::is_final which uses BOOST_IS_FINAL if defined, or is otherwise false. Except now BOOST_IS_FINAL lives in Config, and all the compiler-detection logic lives solely in Config.
What if the compiler intrinsic doesn't work in some cases? Boost.TypeTraits apply workarounds for such cases, so that the official trait works as intended. These workarounds might be impossible or expensive to do within a macro.
Andrey, the macro is not intended to replace the type trait. Both exist today, both will continue to exist. Users who want to use BOOST_IS_FINAL over boost::is_final will continue to do so. Users who want to use boost::is_empty because of it's workarounds over BOOST_IS_EMPTY will continue to do so. The only thing that would change is where the definition of BOOST_IS_FINAL lives. The TypeTraits intrinsic macros are public today and users are using them. They are also all just about compiler detection and mapping to the right intrinsic, nothing more. Them living in Config is not confusing to users, because Config is all about compiler specfic detection anyway. Glen
On 08/23/18 13:40, Glen Fernandes wrote:
On Thursday, August 23, 2018, Andrey Semashev via Boost
mailto:boost@lists.boost.org> wrote: What if the compiler intrinsic doesn't work in some cases? Boost.TypeTraits apply workarounds for such cases, so that the official trait works as intended. These workarounds might be impossible or expensive to do within a macro.
Andrey, the macro is not intended to replace the type trait. Both exist today, both will continue to exist. Users who want to use BOOST_IS_FINAL over boost::is_final will continue to do so. Users who want to use boost::is_empty because of it's workarounds over BOOST_IS_EMPTY will continue to do so. The only thing that would change is where the definition of BOOST_IS_FINAL lives.
I gathered that you intended to use BOOST_IS_FINAL as a way to access a compiler intrinsic, i.e. use it in place of the type trait.
The TypeTraits intrinsic macros are public today and users are using them. They are also all just about compiler detection and mapping to the right intrinsic, nothing more. Them living in Config is not confusing to users, because Config is all about compiler specfic detection anyway.
I didn't find those macros documented. Specifically for BOOST_IS_FINAL, it is mentioned as a *way to detect* whether `boost::is_final` gives the actual result and not just `false`. The docs don't say that BOOST_IS_FINAL is a way to access compiler intrinsics, so if someone is using it this way, he is relying on implementation details.
On Thu, Aug 23, 2018 at 7:22 AM Andrey Semashev wrote:
I gathered that you intended to use BOOST_IS_FINAL as a way to access a compiler intrinsic, i.e. use it in place of the type trait.
Either in place of, or in addition to (doesn't matter to me) but not the type trait alone. Because the trait alone is inadequate, as I mentioned before.
I didn't find those macros documented. Specifically for BOOST_IS_FINAL, it is mentioned as a *way to detect* whether `boost::is_final` gives the actual result and not just `false`. The docs don't say that BOOST_IS_FINAL is a way to access compiler intrinsics, so if someone is using it this way, he is relying on implementation details.
They're documented here: https://www.boost.org/doc/libs/1_68_0/libs/type_traits/doc/html/boost_typetr... Which says: "The hooks for compiler-intrinsic support are defined in boost/type_traits/intrinsics.hpp, adding support for new compilers is simply a matter of defining one of more of the following macros:" And below: "BOOST_IS_FINAL(T) | Should evaluate to true if T is a class type declared with the final specifier" Glen
On 08/23/18 14:28, Glen Fernandes wrote:
On Thu, Aug 23, 2018 at 7:22 AM Andrey Semashev wrote:
I gathered that you intended to use BOOST_IS_FINAL as a way to access a compiler intrinsic, i.e. use it in place of the type trait.
Either in place of, or in addition to (doesn't matter to me) but not the type trait alone. Because the trait alone is inadequate, as I mentioned before.
Then it looks like everything's already in place in Boost.TypeTraits. Why not just use it? (Yes, I remember about circular dependencies; we can solve those, although I don't see it as that much of a problem as the dependency on Boost.MPL would have been.)
I didn't find those macros documented. Specifically for BOOST_IS_FINAL, it is mentioned as a *way to detect* whether `boost::is_final` gives the actual result and not just `false`. The docs don't say that BOOST_IS_FINAL is a way to access compiler intrinsics, so if someone is using it this way, he is relying on implementation details.
They're documented here: https://www.boost.org/doc/libs/1_68_0/libs/type_traits/doc/html/boost_typetr...
Ok, I missed this page, thanks.
On Thu, Aug 23, 2018 at 7:34 AM Andrey Semashev wrote:
On 08/23/18 14:28, Glen Fernandes wrote:
On Thu, Aug 23, 2018 at 7:22 AM Andrey Semashev wrote:
I gathered that you intended to use BOOST_IS_FINAL as a way to access a compiler intrinsic, i.e. use it in place of the type trait.
Either in place of, or in addition to (doesn't matter to me) but not the type trait alone. Because the trait alone is inadequate, as I mentioned before.
Then it looks like everything's already in place in Boost.TypeTraits. Why not just use it?
It was established from the first e-mail in this thread that the reason for not taking a dependency on TypeTraits for BOOST_IS_FINAL was purely the restriction on Core not depending on TypeTraits.
(Yes, I remember about circular dependencies; we can solve those, although I don't see it as that much of a problem as the dependency on Boost.MPL would have been.)
Yes. If that restriction is something we're open to relaxing now, that works. Both would allow use of BOOST_IS_FINAL and BOOST_IS_EMPTY in Core and I don't mind where I obtain them from. I'm addressing the following points: - "The macros don't belong in Config": They don't belong in Config only if John doesn't want to maintain them in Config and wants to maintain them in TypeTraits. They're not out of place in Config otherwise. They are macros mapping to compiler-specific features, implemented purely in terms of compiler detection. Config does a lot more compiler-specific detection macros than any other library in Boost. - "Users should only use the type trait": Not if the type trait alone does not satisfy their needs. For example, the point I made about boost::is_final. Either the macro alone or the macro in conjunction with the type trait would be needed. - "The intrinsic macros are not public": They are most certainly public and have been for a long time. If we decide that we can't allow Core to depend on TypeTraits, then (as long as John is still OK with it) we can move them to Config. Glen
Glen Fernandes wrote:
Yes. If that restriction is something we're open to relaxing now, that works. Both would allow use of BOOST_IS_FINAL and BOOST_IS_EMPTY in Core and I don't mind where I obtain them from.
TypeTraits is a low level library so it's in principle no problem to allow its use in Core. But I wonder if that (the desire to use it in Core) is not an indication of the functionality in question not belonging in Core. Unfocused libraries like "Utility", "Detail", "Core", if left unchecked, tend to attract all kinds of things and grow beyond any reasonable size. And the fact that we artificially restrict what Core components can use serves as a check. Ideally, we shouldn't need such omnibus components at all.
Andrey, the macro is not intended to replace the type trait. Both exist today, both will continue to exist. Users who want to use BOOST_IS_FINAL over boost::is_final will continue to do so. Users who want to use boost::is_empty because of it's workarounds over BOOST_IS_EMPTY will continue to do so. The only thing that would change is where the definition of BOOST_IS_FINAL lives.
The TypeTraits intrinsic macros are public today and users are using them. They are also all just about compiler detection and mapping to the right intrinsic, nothing more. Them living in Config is not confusing to users, because Config is all about compiler specfic detection anyway.
That's sort of true - but we're talking about moving some of them only. Also note that use of these macros outside of type_traits is quite explicitly not supported - many of them do not map simply to the compiler intrinsic, but to the intrinsic plus whatever compiler-specific workarounds are required. And these workarounds require other type_traits. Now at present the is_final and is_empty intrinsics have no workarounds, but I wouldn't rule them out in the future if say the Acme Devastator compiler's __is_final dies with some new C++30 compiler feature. John. --- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus
On Thu, Aug 23, 2018 at 8:16 AM John Maddock wrote:
That's sort of true - but we're talking about moving some of them only.
Right.
Now at present the is_final and is_empty intrinsics have no workarounds, but I wouldn't rule them out in the future if say the Acme Devastator compiler's __is_final dies with some new C++30 compiler feature.
Sure. That scenario would be not very different for various other compiler-specific macros maintained in Config, that may require (in future) more compiler-specific workarounds, no? (e.g. BOOST_ALIGNMENT could find itself in the same boat). (Possible, but unlikely, since for an implementation to regress now with a broken std::is_final or a broken alignas would be very crippling, but you never know...). Glen Glen
On 08/23/18 05:14, Gavin Lambert via Boost wrote:
On 23/08/2018 13:31, Glen Fernandes wrote:
One thing about this suggestion: If Boost.Config was to provide macros that tell users whether Boost.TypeTraits' boost::is_final<T>::value is emulated or the real deal, then the compiler detection logic currently in Boost.TypeTraits for detecting __is_final would already have to be duplicated in Boost.Config. That does not sound like a great idea.
Right now TypeTraits provides both, which is better. i.e. It provides boost::is_final<T>::value and BOOST_IS_FINAL(T). The former uses the latter if it is defined, or is always false if not defined.
If BOOST_IS_FINAL(T) and all its compiler detection logic lives in TypeTraits, then that all that compiler detection logic should not be duplicated in Config to provide a BOOST_HAS_IS_FINAL_INTRINSIC or similar feature detection macro.
What if Boost.Config contained all the compiler detection logic to define BOOST_HAS_IS_FINAL_INTRINSIC or not, and then Boost.TypeTraits had no detection and simply used BOOST_HAS_IS_FINAL_INTRINSIC to then define BOOST_IS_FINAL and boost::is_final<T> appropriately?
I suspect, this would complicate Boost.TypeTraits maintenance, although I might be mistaken. Boost.TypeTraits would still have to check the compilers to see which flavor of intrinsics to use on different compilers or whar workarounds for compiler quirks are required. This means duplication between Boost.Config and Boost.TypeTraits. Also, the sole user of these macros would be Boost.TypeTraits (I assume, noone wants to duplicate that detection logic yet again), so I don't see much value in this division.
On 08/23/18 04:31, Glen Fernandes via Boost wrote:
Andrey Semashev wrote:
I would rather encourage people use type traits, the official interface. Boost.Config or Boost.TypeTraits could provide macros that allow users to detect whether is_final is emulated or is the real deal.
One thing about this suggestion: If Boost.Config was to provide macros that tell users whether Boost.TypeTraits' boost::is_final<T>::value is emulated or the real deal, then the compiler detection logic currently in Boost.TypeTraits for detecting __is_final would already have to be duplicated in Boost.Config. That does not sound like a great idea.
Right now TypeTraits provides both, which is better. i.e. It provides boost::is_final<T>::value and BOOST_IS_FINAL(T). The former uses the latter if it is defined, or is always false if not defined.
If BOOST_IS_FINAL(T) and all its compiler detection logic lives in TypeTraits, then that all that compiler detection logic should not be duplicated in Config to provide a BOOST_HAS_IS_FINAL_INTRINSIC or similar feature detection macro.
I had something like BOOST_HAS_IS_FINAL in mind rather than BOOST_HAS_IS_FINAL_INTRINSIC. I.e. don't expose intrinsics, keep them an implementation detail of Boost.TypeTraits. Yes, such a macro is better placed in Boost.TypeTraits.
participants (5)
-
Andrey Semashev
-
Gavin Lambert
-
Glen Fernandes
-
John Maddock
-
Peter Dimov