Hi folks. I'm looking at the SimObject header, and I see a few things in
there which are marked as part of the API and maybe shouldn't be.
Specifically I'm talking about the Params typedef, and the params() method.
There is also the _params member variable which I can see being a part of
the API since it can be used by other classes to make their own params()
function (more on that below), but the Params typedef is more or less an
implementation detail, and the params() method is essentially worthless
because it returns a SimObjectParams which doesn't have anything except the
object's name in it, and you can already get that with the name() method.

*Params pattern*

This gets to the whole Params params() pattern which is sporadically
implemented in some SimObjects in gem5. This pattern is that a given
SimObject subclass will define a Params typedef which corresponds to its
Params struct type, and then also define a params() method which returns
the _params from SimObject cast up to that type.

The Params typedef itself primarily makes the definition of the constructor
a little more legible, since the FullFooTypeForTheArmISAParams can be
really verbose.

Storing the params struct itself could theoretically serve the purpose of
having a bunch of parameters and not having to create a member variable for
each one, spend a bunch of text copying values over in the constructor,
etc. I think most of the time this is unnecessary, but if an object has
tons of values in it for some reason this could make sense.

The params() method then makes the _params member available with the
appropriate type, so that all the FooParams members are accessible. It also
makes the params struct accessible outside the object which is used in a
place or two to read parameters without there needing to be a member in the
object, and probably some sort of accessor to read it.

There are two main problems with this system. First, when used, it adds a
small but not trivial amount of boilerplate to any given class. Second,
it's very sporadically implemented. I think in a lot of places it's there
just because people aren't sure what it's for or if they need it, so they
just put one there regardless. I think I've done that in the past.

*Alternative*

The existence of the Params type and the params() method could be partially
eliminated by defining a templated params() method which took a SimObject
reference and/or pointer as its first parameter. It could then figure out
what Params struct went with that SimObject type using typedef/template
magic set up by the Params building code, and then perform the appropriate
cast.

This has three downsides, two minor and one more serious. The minor one is
that when a class uses this method internally, it would have to do
something like params(this) instead of just params(). That's a fairly minor
difference and not that big a deal. For external consumers that would be
less of a problem since it would change from foo->params() to params(foo).

The second minor issue is that the name params() is very short, and likely
to collide with other names. We could define that with SimObject as a
static method, but then that would make foo->params() turn into the more
verbose SimObject::params(foo), or (and I haven't checked if this is legal
syntax) the more odd looking foo->params(foo). The params() class can't be
a non-static method, because then the type of "this" would be fixed by
where it was defined, meaning it would not cast _params to the right type.
I was not able to find any mechanism in c++ that would let you treat "this"
as an argument for template type resolution.

The third more serious problem is that this implicitly breaks the ability
to use two different SimObject types in python to represent the same
SimObject type in C++. I don't know if this happens in practice, and it's
also broken by the original Params pattern, since there can be only one
typedef in a given class. Since Params is applied adhoc manually, something
that is generally not good, it actually avoids this problem by just not
existing anywhere that would break that assumption.

*Other option*

Another option would be to have a templated class which would define a
Params type and a params() method, and inherit that into each SimObject
which wants to have those members. It would itself inherit from its
parameter which would keep the inheritance hierarchy intact, and make it
possible to override Params and params from super classes:

FooObject : public ParamsMembers<SimObject>

This has a similar problem to the above if exactly what Params type to use
is automatic, although here it could be an additional template argument.
This also trades some boilerplate for less boilerplate, has to be applied
manually to any classes that want to take advantage of it, and obfuscates
the definition of those classes.

Gabe
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to