SpECTRE Documentation Coverage Report
Current view: top level - __w/spectre/spectre/docs/DevGuide - Protocols.md Hit Total Coverage
Commit: 37c384043430860f87787999aa7399d01bb3d213 Lines: 0 1 0.0 %
Date: 2024-04-20 02:24:02
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : \cond NEVER
       2             : Distributed under the MIT License.
       3             : See LICENSE.txt for details.
       4             : \endcond
       5             : # Protocols {#protocols}
       6             : 
       7             : \tableofcontents
       8             : 
       9             : # Overview of protocols {#protocols_overview}
      10             : 
      11             : Protocols are a concept we use in SpECTRE to define metaprogramming interfaces.
      12             : A variation of this concept is built into many languages, so this is a quote
      13             : from the [Swift documentation](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html):
      14             : 
      15             : > A protocol defines a blueprint of methods, properties, and other requirements
      16             : > that suit a particular task or piece of functionality. The protocol can then
      17             : > be adopted by a class, structure, or enumeration to provide an actual
      18             : > implementation of those requirements. Any type that satisfies the requirements
      19             : > of a protocol is said to conform to that protocol.
      20             : 
      21             : You should define a protocol when you need a template parameter to conform to an
      22             : interface. Here is an example of a protocol that is adapted from the [Swift
      23             : documentation](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html):
      24             : 
      25             : \snippet Utilities/Test_ProtocolHelpers.cpp named_protocol
      26             : 
      27             : The protocol defines an interface that any type that adopts it must implement.
      28             : For example, the following class conforms to the protocol we just defined:
      29             : 
      30             : \snippet Utilities/Test_ProtocolHelpers.cpp named_conformance
      31             : 
      32             : The class indicates it conforms to the protocol by (publicly) inheriting from
      33             : `tt::ConformsTo<TheProtocol>`.
      34             : 
      35             : Once you have defined a protocol, you can check if a class conforms to it using
      36             : the `tt::assert_conforms_to` or `tt::conforms_to` metafunctions:
      37             : 
      38             : \snippet Utilities/Test_ProtocolHelpers.cpp conforms_to
      39             : 
      40             : Note that checking for protocol conformance is cheap, so you may freely use
      41             : protocol conformance checks in your code.
      42             : 
      43             : This is how you can write code that relies on the interface defined by the
      44             : protocol:
      45             : 
      46             : \snippet Utilities/Test_ProtocolHelpers.cpp using_named_protocol
      47             : 
      48             : Checking for protocol conformance here makes it clear that we are expecting
      49             : a template parameter that exposes the particular interface we have defined in
      50             : the protocol. Therefore, the author of the protocol and of the code that uses it
      51             : has explicitly defined (and documented!) the interface they expect. And the
      52             : developer who consumes the protocol by writing classes that conform to it knows
      53             : exactly what needs to be implemented.
      54             : 
      55             : Note that the `tt::conforms_to` metafunction is SFINAE-friendly, so you can use
      56             : it like this:
      57             : 
      58             : \snippet Utilities/Test_ProtocolHelpers.cpp protocol_sfinae
      59             : 
      60             : The `tt::conforms_to` metafunction only checks if the class _indicates_ it
      61             : conforms to the protocol. Where SFINAE-friendliness is not necessary prefer the
      62             : `tt::assert_conforms_to` metafunction that triggers static asserts with
      63             : diagnostic messages to understand why the class does not conform to the
      64             : protocol.
      65             : 
      66             : We typically define protocols in a file named `Protocols.hpp` and within a
      67             : `protocols` namespace, similar to how we write \ref DataBoxTagsGroup "tags" in a
      68             : `Tags.hpp` file and within a `Tags` namespace. The file should be placed in the
      69             : directory associated with the code that depends on classes conforming to the
      70             : protocols. For example, the protocol `Named` in the example above would be
      71             : placed in directory that also has the `greet` function.
      72             : 
      73             : # Protocol users: Conforming to a protocol {#protocols_conforming}
      74             : 
      75             : To indicate a class conforms to a protocol it (publicly) inherits from
      76             : `tt::ConformsTo<TheProtocol>`. The class must fulfill all requirements defined
      77             : by the protocol. The requirements are listed in the protocol's documentation.
      78             : 
      79             : Any class that indicates it conforms to a protocol must have a unit test to
      80             : check that it actually does. You can use the `tt::assert_conforms_to`
      81             : metafunction for the test:
      82             : 
      83             : \snippet Utilities/Test_ProtocolHelpers.cpp test_protocol_conformance
      84             : 
      85             : # Protocol authors: Writing a protocol {#protocols_author}
      86             : 
      87             : To author a new protocol you implement a class that provides a `test`
      88             : metafunction and detailed documentation. The `test` metafunction takes a single
      89             : template parameter (typically named `ConformingType`) and checks that it
      90             : conforms to the requirements laid out in the protocol's documentation. Its
      91             : purpose is to provide diagnostic messages as compiler errors to understand why a
      92             : type fails to conform to the protocol. You can use `static_assert`s or trigger
      93             : standard compiler errors where appropriate. See the protocols defined above for
      94             : examples.
      95             : 
      96             : Occasionally, you might be tempted to add template parameters to a protocol. In
      97             : those situations, add requirements to the protocol instead and retrieve the
      98             : parameters from the conforming class. The reason for this guideline is that
      99             : conforming classes will always inherit from `tt::ConformsTo<Protocol>`.
     100             : Therefore, any template parameters of the protocol must also be template
     101             : parameters of their conforming classes, which means the protocol can just
     102             : require and retrieve them. For example, we could be tempted to follow this
     103             : antipattern:
     104             : 
     105             : \snippet Utilities/Test_ProtocolHelpers.cpp named_antipattern
     106             : 
     107             : However, instead of adding template parameters to the protocol we should add a
     108             : requirement to it:
     109             : 
     110             : \snippet Utilities/Test_ProtocolHelpers.cpp named_with_type
     111             : 
     112             : Classes would need to specify the template parameters for any
     113             : protocols they conform to anyway, if the protocols had any. So they might as
     114             : well expose them:
     115             : 
     116             : \snippet Utilities/Test_ProtocolHelpers.cpp person_with_name_type
     117             : 
     118             : This pattern also allows us to check for protocol conformance first and then add
     119             : further checks about the types if we wanted to:
     120             : 
     121             : \snippet Utilities/Test_ProtocolHelpers.cpp example_check_name_type
     122             : 
     123             : # Protocol authors: Testing a protocol {#protocols_testing}
     124             : 
     125             : Protocol authors should provide a unit test for their protocol that includes an
     126             : example implementation of a class that conforms to it. The protocol author
     127             : should add this example to the documentation of the protocol through a Doxygen
     128             : snippet. This gives users a convenient way to see how the author intends their
     129             : interface to be implemented.
     130             : 
     131             : # Protocols and C++20 "Constraints and concepts" {#protocols_and_constraints}
     132             : 
     133             : A feature related to protocols is in C++20 and goes under the name of
     134             : [constraints and concepts](https://en.cppreference.com/w/cpp/language/constraints).
     135             : Every protocol defines a _concept_, but it defers checking its requirements to
     136             : the unit tests to save compile time. In other words, protocols provide a way to
     137             : _indicate_ that a class fulfills a set of requirements, whereas C++20
     138             : constraints provide a way to _check_ that a class fulfills a set of
     139             : requirements. Therefore, the two features complement each other. Once C++20
     140             : becomes available in SpECTRE we can either gradually convert our protocols to
     141             : concepts and use them as constraints directly if we find the impact on compile
     142             : time negligible, or we can add a concept that checks protocol conformance the
     143             : same way that `tt::conforms_to_v` currently does (i.e. by checking inheritance).

Generated by: LCOV version 1.14