Menu

#46 fix infinite recursion if BODY not used for base function calls

1.0.0
accepted
None
Implementation
minor
0.4.0
defect
2012-09-10
2012-05-10
No

If an overriding function does not use BODY() to call the overridden function, contracts go into infinite recursion.
This is an important limitation and I should try to remove it.

I think it is not possible to work around this limitation.
Using object state the library could detect infinite recursion between overriding and overridden function (I prototyped something like this but I am not even sure if this is 100% possible).
However, to break the recursion the base contract will have to call the base body function via static binding (otherwise using dynamic binding, default C++ behaviour for the call, the overriding function will be called causing the recursion).
The contract itself cannot perform the static binding call (e.g., using static_cast<> to the object) because the object state is changed only if pointers/references to the objects are used to call the body, but if pointers/objects are used then C++ uses dynamic binding for the call.
So the contract function could call a special method of the contracted class which performs the static binding call contract_static_binding_body_....

The issue is that such a static binding call will raise a compiler error if the body function is pure virtual -- but can I use SFINAE to get around this compiler error??

The library does not know directly when a function is pure virtual or not so the library will have to define contract_static_binding_body_... also for pure virtual functions and in this case the static binding call B::f() will raise a compile time error.

BUT, could I use templates so the contract_static_biding_body_ is templated and it is not compiled unless called? This way I only get the error if the use calls attempts the static binding for pure virtual??

struct base {
    virtual void call() {
        std::cout << "base call\n";
        // body(); // This causes infinite recursion as it calls deriv::body() via dynamic binding.
        static_binding_body();
    }
    void static_binding_body() {
        std::cout << "base static binding body\n";
        b::body(); // Compiler error for pure virtual body()...
    }
    virtual void body() = 0;
    // {
    // std::cout << "base body\n";
    // }
};

struct deriv: base {
    virtual void call() {
        std::cout << "deriv call\n";
        body();
    }
    virtual void body() {
        std::cout << "deri body\n";
        base::call(); // Causes infinite recursion...
        // base::body(); // This is fine instead.
    }
};

Infinite recursion: deriv::base --> deriv::body --> base::call() --> deriv::body() causing infinite recursion because base::body() is NOT called...

So, at the moment, I did not see a way around this. Programmers have to pay attention and use BODY() for static binding call of the base class.

Discussion

  • Lorenzo Caminiti

    • summary changed from Fix infinite recursion if BODY not used for base function calls to fix infinite recursion if BODY not used for base function calls
    • milestone changed from Release to Future
     
  • Lorenzo Caminiti

    • priority changed from major to minor
    • status changed from new to accepted
     
  • Lorenzo Caminiti

    • milestone changed from Future to 1.0.0
     

Log in to post a comment.