LinkDef #pragma read for modified inheritance

I’m using ROOT v5.34/18. I’m trying to read old data with new class definitions, including a modification to the inheritance structure.

I have older data with the following structure. Let’s call this TMyObject (v1).

[ul][li]TMyObject inherits from TObject[/li][/ul]

TEvent contains a pointer to TMyObject.

TEvent : public TObject { TMyObject* fMyObject; //-> ... ClassDef(TEvent, 1) };

We are changing the framework that calculates TMyObject, and will have the following structure. Call this TMyObject (v2).

[ul][li]TMyObject inherits from TObject.[/li]
[li]TMyObjectOld inherits from TMyObject.[/li]
[li]TMyObjectNew inherits from TMyObject.[/li][/ul]

Now TMyObject (v2) is an empty base class (no data members), and TMyObjectOld has all the data members that TMyObject (v1) used to have.

TEvent contains a pointer to TMyObject (v2), still, but we found that the “//->” notation doesn’t work with a pointer to a base class, so we eliminated it.

TEvent : public TObject { TMyObject* fMyObject; ... ClassDef(TEvent,2) };

The idea is that we can switch between the old and new calculation while downstream code deals only with the base class. We’d like to maintain the base class name of “TMyObject”, though.

To read the old data into the new TMyObjectOld class, I tried to write a “#pragma read” rule into the LinkDef, using the following instructions:

https://root.cern.ch/download/doc/InputOutput.html#manual-data-model-evolution-capabilities

#pragma read\ sourceClass="TEvent" \ targetClass="TEvent" \ source="TMyObject* fMyObject" version="[1]" \ target="fMyObject" \ include="TMyObject.h,TMyObjectOld.h"\ code="{\ TMyObject* my_object = onfile.fMyObject;\ TMyObjectOld* my_object_old = (TMyObjectOld*) my_object_old;\ TMyObjectOld* my_object_new = new TMyObjectOld(my_object_old); fMyObject = my_object_new;\ }"

This doesn’t work, and inspecting what happens, it looks like the “onfile.fMyObject” point is a pointer to random memory, or only a pointer to just the base class TMyObject (v2), and not a pointer to a TMyObject (v1) or a pointer to a TMyObjectOld.

I’ve tried changing the class type in “source=“TMyObject* fMyObject”” to TMyObjectOld, but this doesn’t change anything.

I’ve tried using the oldObj variable that are set up by the “read rules”, but this is apparently a TVirtualObject whose GetObject() methods yields a TStreamerInfo object for “TEvent@@1” (my old event class version on the file on disk. I don’t know what to do with this TStreamerInfo object. Does it somehow contain the data I need?

I’ve tried using the “#pragma readraw” rules and the buffer variable that’s available, but again, I don’t know how to read anything from this. (Also, this gets automatically wrapped in a “#if 0” comment in the Dictionary.cpp, which I have to remove manually.)

I’m working on making a simple example, but that will take me a little time to get together. Is there something obvious I should be doing? Do I have to make a custom streamer for TEvent, and how would that look? Thanks for any help.

[quote]I’ve tried using the oldObj variable that are set up by the “read rules”,[/quote]Unfortunately, they have not yet been implemented.

[quote] it looks like the “onfile.fMyObject” point is a pointer to random memory[/quote]I hope not, this would be a serious bug.

TMyObjectOld* my_object_old = (TMyObjectOld*) my_object_old;should not compiled, but you like meant:TMyObjectOld* my_object_old = (TMyObjectOld*) my_object;which is fatal nonetheless. The type of ‘onfile.fMyObject’ is really TMyObject and since the data member have been removed from it, they have not been read at all. Casting it to the larger TMyObjectOld will lead you to read memory past the end of the allocated memory.

You would really need to use the feature, … which we have not yet implemented either :frowning: …, that enable reading the onfile object without any transformation (An equivalent to reading the information in your TMyObjectOld shape).

To figure out what option you do have, a question:

Does you object’s pointer type really need to stay the base class type rather than the new derived class name?

Cheers,
Philippe.