Skip to content

Conversation

@bakpaul
Copy link
Contributor

@bakpaul bakpaul commented May 13, 2025

Changed:

  • apply
  • applyJ
  • applyJT (x2)
  • applyDJT
  • computeAccFromMapping
  • getJ (x2)
  • createMappedMatrix
  • disable
  • getJs
  • updateK
  • getK
  • buildGeometricStiffnessMatrix

[ci-depends-on https://github.com/sofa-framework/PluginExample/pull/17]
[ci-depends-on https://github.com/SofaDefrost/ModelOrderReduction/pull/159]
[ci-depends-on https://github.com/sofa-framework/BeamAdapter/pull/189]

ℹ️ Need to be discussed

Some methods (such as apply) have been overloaded in child class, now we've got this stange pattern :
Mother::apply -> Mother::doApply(pure virtual) --> Child::apply
Just because we used an oveload


By submitting this pull request, I acknowledge that
I have read, understand, and agree SOFA Developer Certificate of Origin (DCO).


Reviewers will merge this pull-request only if

  • it builds with SUCCESS for all platforms on the CI.
  • it does not generate new warnings.
  • it does not generate new unit test failures.
  • it does not generate new scene test failures.
  • it does not break API compatibility.
  • it is more than 1 week old (or has fast-merge label).

@bakpaul
Copy link
Contributor Author

bakpaul commented May 13, 2025

[ci-build][with-all-tests]

@sofabot
Copy link
Collaborator

sofabot commented May 13, 2025

[ci-depends-on] detected during build #2.

To unlock the merge button, you must

@bakpaul bakpaul added the topic for next dev-meeting PR to be discussed in sofa-dev meeting label May 13, 2025
///
/// If the Mapping can be represented as a matrix J, this method computes
/// $ out = J in $
void doApply (const MechanicalParams* mparams, MultiVecCoordId outPos, ConstMultiVecCoordId inPos ) override;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void doApply (const MechanicalParams* mparams, MultiVecCoordId outPos, ConstMultiVecCoordId inPos ) override;
void doApply (const MechanicalParams* mparams, MultiVecCoordId outPos, ConstMultiVecCoordId inPos ) final;

?

@damienmarchal
Copy link
Contributor

damienmarchal commented May 15, 2025

What a massive work.

I'm surprised by the move from the pure virtual BaseMapping's method to virtual final. To me the purpose of declaring a method virtual with final keyword prevent further re-implementation... and thus is equivalent to a non virtual method.

About the overload of apply()...
The current code is more or less:

BaseMapping
{
public:
     virtual void apply (const MechanicalParams* mparams = mechanicalparams::defaultInstance()) = 0;
};

Mapping : public BaseMapping
{
public:
     void apply (const MechanicalParams* mparams = mechanicalparams::defaultInstance()) override;
     virtual void apply (const MechanicalParams* mparams, OutDataVecCoord& out, const InDataVecCoord& in) = 0;
};

AMapping : public Mapping
{
public: 
     void apply (const MechanicalParams* mparams = mechanicalparams::defaultInstance()) override;
     void apply (const MechanicalParams* mparams, OutDataVecCoord& out, const InDataVecCoord& in) override;
};

After applicaition of the template method pattern I should looks close to:

BaseMapping
{
public:
     // this method is public and non virtual, because we don't want subclass to "tune" (or screw) its internal logical. 
     void apply (const MechanicalParams* mparams = mechanicalparams::defaultInstance()) { 
                // ... common code here....  
                
                // calls the delegate only when pre-requierement/context is fullfill 
                doApply(...); 
                
                // ... other common code here 
     }

// there is a choice between private and protected. 
// the choice depend if the method can be used in isolation in the child classes or if it is not supposed to. 
private:  
     // child class must implement something 
     virtual void doApply(const MechanicalParams* mparams) void = 0; 
};

Mapping  : public BaseMapping
{
private:
     void doApply(const MechanicalParams* mparams) override {
              // the actual implementation providing the service to the "parent class"
              // on this case, apply is actually dispatching to a new level of delegates
              
              // ... common code should be here ...

              doApplyOnCoordinates()
              
              // ... common code should be here ...
     }
     
     // to de-ambiguate the second apply() method introduced in Mapping.h, give it a second name.  
     void doApplyOnCoordinates (const MechanicalParams* mparams, OutDataVecCoord& out, const InDataVecCoord& in) = 0;
};

AMapping : public Mapping
{
private: 
     void doApplyOnCoordinates (const MechanicalParams* mparams, OutDataVecCoord& out, const InDataVecCoord& in) final {
     /// implements things here. 
     }
};

The chaining of delegates with different names makes very explicit what is expected from each method. Because each use of TMP (template method pattern) can be seen as a contract between the base class and its child on the specific, and sole, purpose of the delegated method as well as its context of use.

@bakpaul
Copy link
Contributor Author

bakpaul commented May 15, 2025

It is not equivalent, otherwise the keyword 'final' wouldn't exist... Actually, doing this we make sure no one shadows the method in a child class. You are right that without the virtual keyword, polymorphism will not apply, but it allows some bad coding practice that could lead to very hard to track runtime errors. In my opinion we should keep the final to make sure no one ever overrides it, this will avoid some tricky situations and changes nothing really in the API.

Your suggestion seems good to me, nevertheless, we wanted to keep this first salve of PRs only at the first level of inheritance. Methods introduced at the second level will be treated in a second stage (maybe a new sprint ?). We will keep your comment in mind then !

@hugtalbot hugtalbot removed the topic for next dev-meeting PR to be discussed in sofa-dev meeting label May 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr: breaking Change possibly inducing a compilation error pr: status wip Development in the pull-request is still in progress refactoring Refactor code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants