Let me add to the plate a simple proposal though still a bit verbose and 
probably not that different from a manual cast

Defining a template method in SimObject:

template <class Obj>
Obj params()
{
    return static_cast<Obj>(_params);
    Or more secure:
    param =  dynamic_cast<Obj>(_params);
    assert(param);
    return param;
}

And delegate the type specification on the client side:

For example in my shiny new

Class MyObject : public SimObject {}

I would use

auto p = params<MyObjectParams*>();

You still have to type your param type so that doesn’t make it the best but I 
believe it’s the simplest one

Giacomo

From: Jason Lowe-Power via gem5-dev <[email protected]>
Sent: 22 October 2020 16:26
To: gem5 Developer List <[email protected]>
Cc: Gabe Black <[email protected]>; Jason Lowe-Power <[email protected]>
Subject: [gem5-dev] Re: SimObject params() method

Hey Gabe,

Thanks for bringing this up. I have also been bothered by the lack of 
consistency with how params are used. I can't think of an example of when you 
need to store the params object. I would be all for getting rid of the params() 
function and updating the documentation to say that it's best practice to *not* 
save the params struct after the constructor. If some object had a good reason 
to go against this best practice, that would be OK, and we wouldn't need to 
enforce any specific design or pattern on these exceptions. I would prefer to 
remove the params() function than add more template magic.

On Thu, Oct 22, 2020 at 1:18 AM Gabe Black via gem5-dev 
<[email protected]<mailto:[email protected]>> wrote:
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.

I agree. I think the typedef is useless and shouldn't be in the API. It's 
unfortunate that the API proposals didn't get more reviews. I think it's 
probably OK to just drop that from the API, but the params() function itself is 
going to need to be deprecated.


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.

I think verbose is fine. I would vote to abolish all params typedefs.


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.

I don't think there are any examples of this in the codebase. I think in all 
cases the params data is copied into member variables. If there are cases where 
data isn't copied, I doubt it was with a strong reason in mind. The one 
exception to this might be Ruby, but it's an exception for all the wrong 
reasons ;).


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 -- [email protected]<mailto:[email protected]>
To unsubscribe send an email to 
[email protected]<mailto:[email protected]>
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s
IMPORTANT NOTICE: The contents of this email and any attachments are 
confidential and may also be privileged. If you are not the intended recipient, 
please notify the sender immediately and do not disclose the contents to any 
other person, use it for any purpose, or store or copy the information in any 
medium. Thank you.
_______________________________________________
gem5-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to