MISRA Discussion Forums
9-3-3 and interfaces enforced via templates instead of virtual functions - Printable Version

+- MISRA Discussion Forums (https://forum.misra.org.uk)
+-- Forum: MISRA C++ (https://forum.misra.org.uk/forum-18.html)
+--- Forum: MISRA C++:2008 rules (https://forum.misra.org.uk/forum-19.html)
+---- Forum: 6.9 Classes (C++) (https://forum.misra.org.uk/forum-138.html)
+---- Thread: 9-3-3 and interfaces enforced via templates instead of virtual functions (/thread-1594.html)



9-3-3 and interfaces enforced via templates instead of virtual functions - cgpzs - 15-12-2021

Hi,

We are having trouble following Rule M9-3-3 when implementing interfaces using templates, similarly to the idea of "named requirements". I have read a similar post about this rule here and it's stated that the rule will be revised to also take the "override set" of virtual functions into account, making sure a function should be made const only if the whole "override set" can be made const.

Sometimes it might not be feasible to implement interfaces via virtual functions, and templates can be used to achieve the same result instead:

Code:
template <typename FooT>
void foo(FooT& f)
{
   f.run();
}


This pattern is commonly used e.g. in static dependency injection. We can pass any type `FooT` as long as it fulfills the interface `FooT::run`. For some types, `run` could be made const, but not all of them, therefore we get warnings from our static analyzers in such functions.

Will you consider this use case in the next revision of the rule? How do you suggest we work with it?

Thanks!


RE: 9-3-3 and interfaces enforced via templates instead of virtual functions - misra cpp - 13-01-2022

We're not sure what the problem is that you are concerned about.

If you have class A with  void run() const;  and  class B with  void run();  and the two versions of run satisfy 9-3-3  (i.e. A::run() can be const, but B::run() can't be const), then you can instantiate foo with both A and B.

We can see that you may get a violation of 7-1-2 (make reference parameters const where possibly), but that can be avoided by overloading foo with void foo(const FooT& f)

Please clarify the concern


RE: 9-3-3 and interfaces enforced via templates instead of virtual functions - cgpzs - 14-01-2022

Thanks for the reply. I realize how my example was unclear, let me show a couple more examples.

I think the main confusion with this rule is that "can be const" is ambiguous. What does it mean "can"?

Example 1: I want to implement a STL-like container class. To be consistent with what STL expects ("named requirements"), I need to implement:

Code:
T* data()       { return data_; }  // Violating M9-3-3?
const T* data() const { return data_; }

These two functions are identical and they do not modify the internal state of the class. STL expects all container classes to have these 2 functions for read and write access. However, technically, one "can" add const to the first one, because the function is not modifying the internal state. It's just creating a copy of the internal pointer and returning it. The compiler will accept const and static analyzers will require const. However we will not be able to use this class because it doesn't fulfill the required expectations.

Example 2: this is a slightly off-topic from "interfaces enforced via templates" but still relevant I think; let me know if you'd rather have it in a separate post.

Code:
class Foo
{
public:
    ~Foo() { delete x_; }

    void set(int x)  // Violates M9-3-3? Technically, I "can" add const and the code will compile
    {
       *x_ = x;
    }
    
private:
    int* x_{new int};
};

Here we have a setter, which everyone expects to be "non-const" as it's setting the internal state of the class. However, since it's a pointer, the compiler will accept adding "const". Technically, I "can" add const. But that doesn't mean I "should". Adding const will be against the principle of least surprise and will confuse developers. I'm aware of std::experimental::propagate_const, but naturally we are not going to use experimental features in a safety-critical environment.

Personally, I think it would be good to rephrase this rule in terms of "semantic const", instead of "syntactic const". Or at least clarify precisely what it's meant by "can be const".

Looking forward to your thoughts!


RE: 9-3-3 and interfaces enforced via templates instead of virtual functions - misra cpp - 26-01-2022

The rule as drafted was intended to just cover 'syntactic const', but we recognise that this has limitations.

In this case, you'll need to deviate, or artificially modify the function so that it cannot be made const.


RE: 9-3-3 and interfaces enforced via templates instead of virtual functions - cgpzs - 26-01-2022

Understood, thank you very much for the discussions!


RE: 9-3-3 and interfaces enforced via templates instead of virtual functions - misra cpp - 18-02-2022

You're welcome.

This thread is now closed, please post any follow-on questions as new threads.

(we need to make the last post on a thread, so we can spot which threads have unanswered posts)