Skip to content

Make member pointer fEvtHeader of FairRun into unique pointer #1254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 7, 2023

Conversation

YanzhaoW
Copy link

@YanzhaoW YanzhaoW commented Nov 9, 2022

Encapsulate member pointer FairEventHeader from FairRun inside std::unique_ptr. This specifies the ownership of the event header and prevents it from being deleted multiple times.

Fixes #1242

Checklist:

@YanzhaoW
Copy link
Author

YanzhaoW commented Nov 9, 2022

For a short remark, I would suggest there should be no more delete operator in the FairRoot. For the new operator, except for some ROOT build-in classes, instead use

std::make_unique<typename> ptr;
// or
std::make_shared<typename> ptr;

Copy link
Member

@ChristianTackeGSI ChristianTackeGSI left a comment

Choose a reason for hiding this comment

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

Many thanks for your PR!
I like most of it!

I added a few comments here and there.

And you might possibly want to wait for #1255 getting merged and then rebase on it?

@@ -82,6 +82,7 @@ class FairRunAnaProof : public FairRunAna
FairRunAnaProof operator=(const FairRunAnaProof&);

FairFileSource* fProofFileSource;
FairEventHeader* fEvtHeader = nullptr;
Copy link
Member

Choose a reason for hiding this comment

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

Which code in FairRunAnaProof initalizes it to the real pointer?

Copy link
Author

@YanzhaoW YanzhaoW Dec 5, 2022

Choose a reason for hiding this comment

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

Initialisation of event header is in FairRun. And pointer fEvtHeader in FairRunAnaProof is not owned.

Copy link
Member

Choose a reason for hiding this comment

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

This one is private to FairRunAnaProof. So only FairRunAnaProof can initialize it?

Copy link
Author

Choose a reason for hiding this comment

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

Oh, it seems I misunderstood the "initialisation" of the pointer. If it means assigning a valid address to the pointer, ah, yes, only FairRunAnaProof can initialise it:

fEvtHeader = dynamic_cast<FairEventHeader*>(fRootManager->GetObject("EventHeader."));

That's the only place when it's assigned. And in the Init() function the pointer cannot be guaranteed to have a valid memory address. I will make a change about it very soon. (also in other classes).

Comment on lines 210 to 214
/** MC Event Header */
std::unique_ptr<FairEventHeader> fEvtHeader; //!
Copy link
Member

Choose a reason for hiding this comment

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

I really appreciate, that you're making this private.

But maybe let's do things step by step and keep it protected for the time being and fix up all those users that can't handle a unique_ptr? The major one is probably FillEventHeader(). I had #1255 in my private tree anyway and thought it's now a good time for it. It should make this much simpler. So maybe you might want to wait for it getting merged and then rebase?

Copy link
Author

Choose a reason for hiding this comment

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

I would rather like to keep it private. If I make it protected (, which I tried in the very first beginning), lots of places would need to be revised because of of the naming. If other derived class need to use this private pointer, just call the function GetEventHeader()

Copy link
Member

Choose a reason for hiding this comment

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

Hmmm. Good point!

Could you look into replacing many of the fEvtHeader in the derived classes by GetEventHeader(), or local variables that get initialized by GetEventHeader()? I think, that would make the whole thing more consistant.

Looking at FairRunAnaProof.cxx

fEvtHeader = dynamic_cast<FairEventHeader*>(fRootManager->GetObject("EventHeader."));

That's really confusing. Not to mention I still have trouble to understand whether GetObject returns an owning pointer or not. I guess, it's not owning for now. Which means that the delete in FairRun, that we had before, is wrong.

Copy link
Author

@YanzhaoW YanzhaoW Dec 5, 2022

Choose a reason for hiding this comment

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

How about changing it to

fEvtHeader = GetEventHeader();

I don't understand why the event header must be obtained from GetObject? Or they are two different event headers? one from FairRun and another from FairRootManager?

And I don't think GetObject() and Register() from FairRootManager have anything about ownership transferring. Please correct me if I'm wrong.

Copy link
Member

Choose a reason for hiding this comment

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

Thinking again about it…

fEvtHeader = dynamic_cast<FairEventHeader*>(fRootManager->GetObject("EventHeader."));

I think, this assumed (in the current version), that GetObject returns a fresh/new object. Because currently the destructor of FairRun deletes it.

So what about replacing this just with SetEventHeader(…)? Then the unique_ptr will do the delete (again).

Copy link
Author

Choose a reason for hiding this comment

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

Yeah, I would also do this. Event header should be directly obtained from FairRun every time for the consistency.

Copy link
Member

@ChristianTackeGSI ChristianTackeGSI Feb 9, 2023

Choose a reason for hiding this comment

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

The current status of #1346 consludes that GetObject returns a non-owning pointer. So the current code that just assigns to fEvtHeader (and lets the destructor of FairRun delete it) would be wrong.

I think, we should first resolve this, before going further?

@YanzhaoW
Copy link
Author

@ChristianTackeGSI Thanks for your comments. Sure, let's pend this PR until #1255 is merged.

@dennisklein
Copy link
Member

FYI, c4ced68 has landed in the dev branch

@karabowi
Copy link
Collaborator

@YanzhaoW , can you squash your commits into one, and then add one extra commit with your name in the CONTRIBUTORS file?

@YanzhaoW
Copy link
Author

@karabowi Sorry. Yes, sure. But I still need some time and to rebase it on c4ced68 commit. After I finish, I will squash it to one commit.

@YanzhaoW YanzhaoW force-pushed the ywang_fairroot branch 2 times, most recently from d950265 to 0e2c56b Compare December 5, 2022 11:59
@YanzhaoW
Copy link
Author

YanzhaoW commented Dec 5, 2022

@karabowi Hi, all is done now.

Copy link
Member

@ChristianTackeGSI ChristianTackeGSI left a comment

Choose a reason for hiding this comment

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

Looks good!

Could you add an entry to the CHANGELOG? Really, derived classes from FairRun and friends will no longer see an fEvtHeader. So I would call that at least an interesting change (maybe "breaking"?).

@@ -82,6 +82,7 @@ class FairRunAnaProof : public FairRunAna
FairRunAnaProof operator=(const FairRunAnaProof&);

FairFileSource* fProofFileSource;
FairEventHeader* fEvtHeader = nullptr;
Copy link
Member

Choose a reason for hiding this comment

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

This one is private to FairRunAnaProof. So only FairRunAnaProof can initialize it?

@@ -15,6 +15,7 @@
* @since 28.02.05
*/

#include "FairEventHeader.h"
Copy link
Member

Choose a reason for hiding this comment

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

Is this really needed?

Copy link
Author

Choose a reason for hiding this comment

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

I'm very glad you ask about this. :D Yes, somehow a simple alternative like class FairEventHeader; surprisingly doesn't work. That's the reason why it took me so much time.

The reason behind it is ROOT ( of course, like always! ). If you remove ClassDefOverride in the end of the file, class FairEventHeader works. And about why it works without ClassDefOverride, I have no idea.

Comment on lines 210 to 214
/** MC Event Header */
std::unique_ptr<FairEventHeader> fEvtHeader; //!
Copy link
Member

Choose a reason for hiding this comment

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

Hmmm. Good point!

Could you look into replacing many of the fEvtHeader in the derived classes by GetEventHeader(), or local variables that get initialized by GetEventHeader()? I think, that would make the whole thing more consistant.

Looking at FairRunAnaProof.cxx

fEvtHeader = dynamic_cast<FairEventHeader*>(fRootManager->GetObject("EventHeader."));

That's really confusing. Not to mention I still have trouble to understand whether GetObject returns an owning pointer or not. I guess, it's not owning for now. Which means that the delete in FairRun, that we had before, is wrong.

@YanzhaoW
Copy link
Author

YanzhaoW commented Dec 5, 2022

Ok, I made additional changes to prevent calling the member functions of FairEventHeader when it's nullptr.

I'm not sure which of them are really necessary and which are not. The event header is used in all derived classes of FairRun and some of them are doing exactly the same thing. I would suggest better put those steps in the member function of FairRun and call it when necessary. This could make the code much more maintainable.

Comment on lines 510 to 512
if(!fEvtHeader)
fEvtHeader = GetEventHeader();
tmpId = fEvtHeader->GetRunId();
Copy link
Member

Choose a reason for hiding this comment

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

I don't really like that we have to check each instance of ->GetRunId() for fEvtHeader being set…

What do you think about this (you might want to cherry-pick it into your branch?)

Copy link
Member

@ChristianTackeGSI ChristianTackeGSI left a comment

Choose a reason for hiding this comment

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

Hi, excuse me for being late…

By now, we had another round of fEvtHeader usage cleanup: f7091f7

So could you try a rebase, please?

CONTRIBUTORS Outdated
@@ -32,6 +32,7 @@ Shahoyan, Ruben
Stockmanns, Tobias
Ustyuzhanin, Andrey
von Haller, Barthélémy
Wang, Yanzhao
Copy link
Member

Choose a reason for hiding this comment

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

BTW, if you have an ORCiD, append it like this
Family, Give [https://orcid.org/0000-XXXX-XXXX-XXXX].

Copy link
Author

Choose a reason for hiding this comment

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

Ok, thanks for the info.

Comment on lines 210 to 214
/** MC Event Header */
std::unique_ptr<FairEventHeader> fEvtHeader; //!
Copy link
Member

Choose a reason for hiding this comment

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

Thinking again about it…

fEvtHeader = dynamic_cast<FairEventHeader*>(fRootManager->GetObject("EventHeader."));

I think, this assumed (in the current version), that GetObject returns a fresh/new object. Because currently the destructor of FairRun deletes it.

So what about replacing this just with SetEventHeader(…)? Then the unique_ptr will do the delete (again).

@@ -100,6 +100,7 @@ class FairRunAna : public FairRun
private:
FairRunAna(const FairRunAna& M);
FairRunAna& operator=(const FairRunAna&) { return *this; }
FairEventHeader* fEvtHeader = nullptr;
Copy link
Member

Choose a reason for hiding this comment

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

Having another thought about this as well:

Could you try to not use member variables, but use local variables in the methods that need fEvtHeader?

Like

FairRunAna::DoFoo() {
    auto fEvtHeader = GetEventHeader();
    …
    // code that actually needs fEvtHeader

that way the relevant methods havr access to the current value and not just an old one?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, this is a better way.

@YanzhaoW
Copy link
Author

YanzhaoW commented Feb 9, 2023

Hi, @ChristianTackeGSI

Here are some changes from the latest commit (82c9a19):

  1. From CHANGELOG file, you can see I deprecate two member functions in FairRun to make them more readable and safer.
  2. Remove private member of FairEventHeader from FairRunAna, FairRunOnline and FairRunAnaProof.
  3. Delete all lines which obtain the eventHeader from FairRunManager::GetObject(). Which makes the eventHeader of the whole program consistent with the one from FairRun::GetEventHeader().

Please check the commit and see whether the changes break anything not wanted.

Copy link
Member

@ChristianTackeGSI ChristianTackeGSI left a comment

Choose a reason for hiding this comment

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

The whole GetObject is gone. Maybe that's good, because it avoids all the discussion of #1346. But I am not sure, whether it was needed?

We'll try to discuss this in the team very soon.
(ping @karabowi @fuhlig1 – we'll try to discuss this on Monday.)

Comment on lines 243 to 246
fEvtHeader = dynamic_cast<FairEventHeader*>(fRootManager->GetObject("EventHeader."));

if (nullptr == fEvtHeader)
LOG(fatal) << "Could not read event header.";
Copy link
Member

Choose a reason for hiding this comment

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

Also relevant to this.

if (par) {
fEvtHeader = static_cast<FairEventHeader*>(fRootManager->GetObject("EventHeader."));
Copy link
Member

Choose a reason for hiding this comment

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

Also relevant to this.

@ChristianTackeGSI
Copy link
Member

Hi @YanzhaoW!

We concluded this morning, that GetObject does not return an owning pointer (as already stated in #1346). @karabowi will take a look at FairRun and friends, how GetObject is used for the EventHeader.

Many thanks for your patience!

@YanzhaoW
Copy link
Author

Hi, @ChristianTackeGSI. Are there any updates from @karabowi about this PR?

@ChristianTackeGSI
Copy link
Member

Hi!

Thanks for asking!

We're still stuck in the first point of #1346 (looking at the semantics of GetObject in FairRunAnaProof).
I hope @karabowi can take a look at it next week maybe. Let's see, what he says…

@karabowi
Copy link
Collaborator

Experiment tests are being performed now to check if we can change the FairRunOnline and remove GetObject.

@ChristianTackeGSI
Copy link
Member

Hi @YanzhaoW!

Now that #1396 has been merged, I think, the last case with a strange fEvtHeader access has been removed.

Can you try a rebase please?

@YanzhaoW YanzhaoW force-pushed the ywang_fairroot branch 2 times, most recently from e6dd0ca to 2f1f7ec Compare June 20, 2023 10:01
Comment on lines 216 to 217
fEvtHeader->Register(GetSink() ? fStoreEventHeader : false);
evtHeader->Register(fStoreEventHeader);
Copy link
Member

Choose a reason for hiding this comment

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

We added the GetSink checks on purpose. Can you please keep them?

Copy link
Author

Choose a reason for hiding this comment

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

Sure

Copy link
Member

@ChristianTackeGSI ChristianTackeGSI left a comment

Choose a reason for hiding this comment

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

Please take a look at the compile errors from the CI.

Please consider squashing your commits together.

I added a few more comments inline.

Comment on lines 435 to 436
FillEventHeader();
FillEventHeader(GetEventHeader());
Copy link
Member

Choose a reason for hiding this comment

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

TBH (To Be Honest), I don't understand, why you deprecated FillEventHeader() if you then change it here for example to do exactly what the () variant is doing?

I see FillEventHeader() as the "use the main event header from the current run. And you're just replicating that here?

Copy link
Author

@YanzhaoW YanzhaoW Jun 20, 2023

Choose a reason for hiding this comment

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

Hi. By doing so, my idea was that the function FillEventHeader takes the event header as a parameter and therefore is independent of the event header intrinsically. It's a very subtle change. IMO, it's more readable and less error-prone. Otherwise, one possibility to make an error is to change the event header inside the FillEventHeader().

But now I think we should get just rid of it. Instead we could add a getter for the fSource and directly fill the event header from the source. I think it's more clearer in this way.

There is another reason if we consider a little bit design. Basically a good design should only allow one way access and therefore one way for the change. Everything else should be closed.

Copy link
Member

Choose a reason for hiding this comment

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

I learned about the Facade pattern from @dennisklein. And yes, I think, FillEventHeader() and GetEvtHeaderRunId() are facades.

And we're not trying to hide anything away. First, these are internal member functions. Not meant for public use (at least not yet). Second, the full source is available anyway.

I tried to improve documentation with #1413.

Copy link
Author

Choose a reason for hiding this comment

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

From my understanding, the Facade design pattern involves with a Facade object that provides a simpler public interface to a complicated underlying system. But here the function FillEventHeader() just provide an additional way to modify its private member variable.

Protected functions are still not private, which means any derived class could expose the functionality to the public.

However the question remains: there are two paths/ways to do one thing. This could further cause additional problems:

  1. Confusing to users.
    Which way should I choose?
auto* evtHeader = run->GetEventHeader();
auto* source = run->GetSource();
source->FillEventHeader(evtHeader);

or

run->FillEventHeader();
  1. Bug-prone and difficult to maintain.
    Supposing that in the future there is a change for the function FillEventHeader(), the code using the second way could have this new implementation. But other code using the first method still has the old implementation even though these two method are meant to do exactly the same thing.

Copy link
Member

Choose a reason for hiding this comment

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

Protected functions are still not private, which means any derived class could expose the functionality to the public.

Those functions have been declared (via documentation) as internal in #1413. If someone outside FairRoot uses them, they're entirely on their own. If this is actually a concern, we could mark them as private: and use friend to allow all the relevant users inside FairRoot. But TBH I don't like that either: At some point, I like it, if things are private even inside FairRoot.

Point (1) then isn't relevant: Only possibly confusing to FairRoot developers. My take on that one: Use the shorter API, so that the caller is easier to read (which is really an important point in our current codebase).

Point (2) is also only relevant to FairRoot developers. But that conern is a problematic point of the facade pattern at all. So yes, FairRoot devs have to take care.

Comment on lines 485 to 470
auto const tmpId = GetEvtHeaderRunId();
auto const tmpId = GetEventHeader()->GetRunId();
Copy link
Member

Choose a reason for hiding this comment

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

Same here… I don't understand, why you need to change this? GetEvtHeaderRunId(); seems to have a nice API?

Copy link
Author

Choose a reason for hiding this comment

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

This is the same reason as above.

@YanzhaoW
Copy link
Author

Hi, @ChristianTackeGSI

Thanks for your comments. Sorry for the delay. I made few corrections and will squash the commits once everything is considered ok. Please check my replies and ask me if you have more questions or suggestions.

@YanzhaoW YanzhaoW force-pushed the ywang_fairroot branch 2 times, most recently from 9c4bc88 to ef23c7e Compare June 20, 2023 12:48
@YanzhaoW
Copy link
Author

The compilation is successful. But I got a segmentation error from ctest "ex_tutorial3_reco_timebased_TGeant4". Other ctests work fine.

Copy link
Member

@ChristianTackeGSI ChristianTackeGSI left a comment

Choose a reason for hiding this comment

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

Just a short quick note… I will look into this more on Friday (hopefully).

Comment on lines 534 to 519
FillEventHeader();
GetSource()->FillEventHeader(GetEventHeader());
Copy link
Member

Choose a reason for hiding this comment

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

I think, this one is causing the final segmentation fault, because GetSource might return a nullptr. The old FillEventHeader() catches this (withut giving a warning…)

@@ -247,16 +249,19 @@ class FairRun : public TNamed
/**
* Call FillEventHeader on the source
*/
void FillEventHeader()
[[deprecated("Use GetSource()->FillEventHeader()")]] void FillEventHeader()
Copy link
Member

Choose a reason for hiding this comment

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

If we recommend to unconditionally dereference the return value of GetSource(), we should also make sure it never returns a nullptr, right?

The C++ idiomatic way to communicate this would be to return a reference instead of a raw pointer, but FairRoot rarely uses references ..

Perhaps we should add new safer-to-use APIs to support call chains?

FairSource& GetDataSource();
FairSource const& GetDataSource() const;

GetEventHeader()'s implementation currently guarantees not to return a nullptr, but I would still add a comment to the header file documenting this intended post condition that it does not get violated in the future by accident. Additionally, we should add unit tests.

Copy link
Author

@YanzhaoW YanzhaoW Jun 23, 2023

Choose a reason for hiding this comment

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

Yes, the common way for a getter function is to return a const ref. Returning a raw pointer requires the caller to constantly check whether it's a nullptr.

We could implement additional getters to return references. But for GetSource(), is it possible to do one of these?

  1. Throw an exception std::runtime_error() if the source is nullptr.
  2. Use return gsl::not_null<FairSource*>. This will call std::terminate automatically when fSource is a nullptr. By this way we don't need to change the API.

Copy link
Member

Choose a reason for hiding this comment

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

I would love to fix some of the return types of existing member functions, but how can one do that gracefully in C++ (with a deprecation period)?

Copy link
Author

@YanzhaoW YanzhaoW Jun 23, 2023

Choose a reason for hiding this comment

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

Assuming we are not going to break API, gsl::not_null is pretty good shot for those member functions returning a pointer.

For reference, I think we need two getters returning const ref and ref:

auto Get_cref() -> const Type&;
auto Get_ref() -> Type&;

I wouldn't say the following is a good choice:

auto Get() const -> const Type&;
auto Get() -> Type&;

because in many cases when the object is not a const, we still need to get a const ref of its member variable for the reading. Some classes like FairRun can never be a const. But getting a const ref of, for example, event header for its reading is still necessary.

@YanzhaoW
Copy link
Author

YanzhaoW commented Jun 23, 2023

Hi, @dennisklein @ChristianTackeGSI

I found why there is a crash in that test:

FairRunAna *fRun = new FairRunAna();
FairFileSource *fFileSource = new FairFileSource(inFile);
fRun->SetSink(std::make_unique<FairRootFileSink>(outFile));
fRun->RunWithTimeStamps();
fRun->SetUseFairLinks(kTRUE);

The source file fFileSource is not used at all. And of course the member variable fSource in FairRun is nullptr. I would say this test should not have even passed the current CI workflow.

@ChristianTackeGSI
Copy link
Member

@YanzhaoW wow, good catch!

Could you please open an issue for this?

Some of the main developers should take a look at this, really.

I still wonder, whether running without a Source is a valid scenario at all. (Running without a Sink has lately been declared a valid scenario.)

@YanzhaoW
Copy link
Author

YanzhaoW commented Jul 3, 2023

Hi, @ChristianTackeGSI

I have changed them back to FillEventHeader() and also rebased them to the head of the dev branch.

For this PR, I only made eventHeader to be a private unique_ptr of FairRun. Other issues, such as filling the event header many times and its mysterious ownership from FairRootManager (see #1418 ) , is not addressed.

If everything is alright, I will squash my commits for the merging.

Copy link
Member

@ChristianTackeGSI ChristianTackeGSI left a comment

Choose a reason for hiding this comment

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

Hi!

Many thanks for keeping track on this, really!

I appreciate your work and that you keep with this stuff.

My comments are really meant to improve things. And if you think, that something is too much work, please let me know, then I'll try to take over that part.

Comment on lines 261 to 266
UInt_t GetEvtHeaderRunId() const { return fEvtHeader->GetRunId(); }
[[deprecated("Use GetEventHeader()->GetRunId()")]] UInt_t GetEvtHeaderRunId() const
{
return fEvtHeader->GetRunId();
}
Copy link
Member

Choose a reason for hiding this comment

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

Can we please also keep GetEvtHeaderRunId() for the same reason we keep FillEventHeader()?

Copy link
Author

@YanzhaoW YanzhaoW Jul 4, 2023

Choose a reason for hiding this comment

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

Sorry, I still don't understand this style.

FairEventHeader has other getters, like GetInputFiledID, GetEventTime, etc. Does that mean we should also define GetEvtHeaderInputFieldID, GetEvtEventTime, etc in FairRun? If so, we should do the same for fSource. And in the end, FairRun could be filled with more than hundreds of getters and setters.

Copy link
Member

Choose a reason for hiding this comment

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

These are only intended for internal use in FairRun{,Ana,Sim} and not for public use. And so we only have "helpers" for exactly the few interactions with FairEventHeader, that happen often enough in FairRun*, that it is worth to have an internal helper that simplifies internal use. And yes, for FairSource or FairSink, we could have those internal helpers, if they simplify things.

At least that was my idea when I introduced some of these.

Copy link
Author

Choose a reason for hiding this comment

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

Sorry, I can't agree that those internal helper functions simplify things. There is nothing to simplify if there are just one or two lines of code. And on the contrary, it makes things more unreadable and less transparent. For example, from the name of FillEventHeader(), it's difficult to say to where this event header is filled and why it's related to a file source. Same goes for GetEvtHeaderRunId(). It means just one line of code evtHeader->GetRunId() and makes the code less transparent.

I think we should try to write a clean code. And a clean code includes no unnecessary interface or internal method. Sorry about wasting the time for this argument. Maybe a third person opinion could help us address this issue more quickly? @dennisklein

Copy link
Member

@dennisklein dennisklein Jul 5, 2023

Choose a reason for hiding this comment

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

Unfortunately, I don't have a good argument to add, which would favor one over the other 🙈

However, I would like to repeat the comment I made earlier. If such a recommendation like GetEventHeader()->GetRunId() (call chain, which unconditionally de-references returned raw pointers) would be added, let's make some effort it is not going to be dangerous code. (I know there is already a good share of unsafe APIs and not-so-safe coding practices in FairRoot/ROOT, but if we never start to address them, the situation will never improve, even though it is only tiny steps)

Copy link
Member

Choose a reason for hiding this comment

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

I have one proposal:

Let's reduce the diff for this PR to the minimum that's absolutely needed to get fEvtHeader made into a private unique_ptr.
Then let's have a distinct PR that "cleans up" the situation. That way the main maintainers (@karabowi, @fuhlig1) can look at it and decide what they like better.

Copy link
Author

Choose a reason for hiding this comment

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

I agree ;D

@YanzhaoW
Copy link
Author

YanzhaoW commented Jul 4, 2023

@ChristianTackeGSI
Thanks for your comments. Most of issues you found are probably due to some confusions when I resolve merge conflicts. I will fix them as soon as possible.

@YanzhaoW YanzhaoW force-pushed the ywang_fairroot branch 2 times, most recently from 9e5179e to 80efc0a Compare July 6, 2023 17:37
@YanzhaoW
Copy link
Author

YanzhaoW commented Jul 6, 2023

Hi, @ChristianTackeGSI
I have squashed all commits into one. If there is nothing else, it's ready to be merged.

Copy link
Member

@ChristianTackeGSI ChristianTackeGSI left a comment

Choose a reason for hiding this comment

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

I like this! We can merge this really, really soon.

I have only a small stylistic request (really tidying up things) for the CHANGELOG.

CHANGELOG.md Outdated
Comment on lines 86 to 90
* `fEvtHeader` member variable now is a private unique pointer owned by `FairRun`. To access
the event header, please use the public member function `GetEventHeader()`.
* `FairRun::SetEventHeader(FairEventHeader*)`,
use `FairRun::SetEventHeader(std::unique_ptr<FairEventHeader> EvHeader)`, which
indicates the ownership transferring.
Copy link
Member

@ChristianTackeGSI ChristianTackeGSI Jul 6, 2023

Choose a reason for hiding this comment

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

  1. Some really small suggestions:
Suggested change
* `fEvtHeader` member variable now is a private unique pointer owned by `FairRun`. To access
the event header, please use the public member function `GetEventHeader()`.
* `FairRun::SetEventHeader(FairEventHeader*)`,
use `FairRun::SetEventHeader(std::unique_ptr<FairEventHeader> EvHeader)`, which
indicates the ownership transferring.
* `fEvtHeader` member variable now is a private unique pointer owned by `FairRun`. To access
the event header, please use the public member function `GetEventHeader()`.
* `FairRun::SetEventHeader(FairEventHeader*)` got deprecated,
use `FairRun::SetEventHeader(std::unique_ptr<FairEventHeader> EvHeader)`, which
indicates the ownership transferring.
  1. Please reorder a bit:
    • The change of fEvtHeader is actually breaking (because derived classes can't any longer acces it). Could you move that bullet point under the "Breaking Changes" subsection?
    • And the other one is a deprecation. We also have a subsection for deprecations. Could you move it there?

Copy link
Author

Choose a reason for hiding this comment

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

Sure, no problem.

Copy link
Author

Choose a reason for hiding this comment

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

Fixed.

@ChristianTackeGSI ChristianTackeGSI merged commit 346473d into FairRootGroup:dev Jul 7, 2023
@ChristianTackeGSI
Copy link
Member

@YanzhaoW many thanks for this! This looks so good!

I have created #1423 which depends on your stuff. Maybe you could leave a Review there?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants