You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The current design of the streamer type hierarchy (including versioning) works in a way which I do not find nice at all. At some point I thought it would be a nice solution but now I see a lot of code repetitions.
A lot of streamer logic is currently implemented in bootstrap.jl and the overall implementation of a streamer and all of its versions is done like this:
As seen above, the ROOTStreamedObject is the supertype (which is just a simple abstract type) and there is (always) one single subtype (another abstract type) representing a specific streamer.
Different versions are defined by appending _VERSION to the type name and creating an empty struct. The readfields! method then define how to read its fields.
Both versions of TAttLine (v1 and v2) have the same fields with the same types, so in this case it's just code repetition.
Note that this definitions should be created dynamically in future, but the overall layout is of course the same.
During the read-in of a ROOT file, UnROOT checks if there is a streamer with the given name and version (appended), like TAttLine_2 and if not, it will complain. (later it will define it from the streamer info).
A simplification of this system which allows a nice bootstrapping (no code repetition) and a better version management would be something like the following:
import Base: getproperty
abstract type ROOTStreamedObject endfunction Base.getproperty(obj::ROOTStreamedObject, sym::Symbol)
if!haskey(Core.getproperty(obj, :fields), sym)
error("Type $(typeof(obj)) has no field $(String(sym))")
end
Core.getproperty(obj, :fields)[sym]
endstruct TAttLine{V} <:ROOTStreamedObject# this should be a macro
fields::Dict{Symbol, Any}end
where the actual struct definition could of course be simplified via a macro like @rootstreamer TAttLine or so.
The readfields!() methods can then be defined using value type dispatch:
julia> tattline =TAttLine{1}(Dict(:fLineColor=>42, :fLineStyle=>5, :fLineWidth=>23))
TAttLine{1}(Dict{Symbol,Any}(:fLineWidth=>23,:fLineColor=>42,:fLineStyle=>5))
julia> tattline.fLineWidth
23
julia> tattline.fFoo
ERROR: Type TAttLine{1} has no field fFoo
This is just an idea, any feedback is highly appreciated ;)
The text was updated successfully, but these errors were encountered:
created dynamically
(later it will define it from the streamer info)
I have time and started looking at the code base again. I'm wondering if it's possible to document an implementation-independent way in a Developers / Internals section of the docs so people can understand how conceptually it works.
Particularly, I am yet to understand how to make a struct for a streamer that we have never seen before, my guess is that the name of streamer and byte # for each field are encoded in TKey(?) or somewhere, but if that is the case does this mean we don't have to do any bootstrap except for the TKey(which is ~fixed) and the starting 37(or 75) bytes of the .root files?
Oh dear, I somehow forgot to answer this. I thought I did 🤔
Anyways, the construction of the struct and also the complete parsing of the structures is very complex. There is a Google group where I also participate in and we were already thinking about writing a book or so about the ROOT I/O to consolidate our knowledge. But I don't know about the time-scale, probably not this year...
The current design of the streamer type hierarchy (including versioning) works in a way which I do not find nice at all. At some point I thought it would be a nice solution but now I see a lot of code repetitions.
A lot of streamer logic is currently implemented in
bootstrap.jl
and the overall implementation of a streamer and all of its versions is done like this:As seen above, the
ROOTStreamedObject
is the supertype (which is just a simple abstract type) and there is (always) one single subtype (another abstract type) representing a specific streamer.Different versions are defined by appending
_VERSION
to the type name and creating an empty struct. Thereadfields!
method then define how to read its fields.Both versions of
TAttLine
(v1 and v2) have the same fields with the same types, so in this case it's just code repetition.Note that this definitions should be created dynamically in future, but the overall layout is of course the same.
During the read-in of a ROOT file, UnROOT checks if there is a streamer with the given name and version (appended), like
TAttLine_2
and if not, it will complain. (later it will define it from the streamer info).A simplification of this system which allows a nice bootstrapping (no code repetition) and a better version management would be something like the following:
where the actual struct definition could of course be simplified via a macro like
@rootstreamer TAttLine
or so.The
readfields!()
methods can then be defined using value type dispatch:Here is a short demo of the instantiation:
This is just an idea, any feedback is highly appreciated ;)
The text was updated successfully, but these errors were encountered: