Trick needed - passing a large number of parameters to a class

E

eran

Hi all,

There's a huge class in our app that I'd like to fragment a bit. I'd
like to move some of the code to a new class. The new class will have
to get a large number of parameters in order to do its job. As I see
it, there are 3 ways of setting that bunch of params:
- Pass them all as argument to one function
- Set each one of them
- Use a params struct
What bothers me is this: I'd really like to minimize the chance that
the caller will miss setting one of the params. The first way will
avoid that, but passing a large number of params to a function is
ugly. There might not be a better solution, but in case I'm missing
something, I'd like to know if there's any elegant way to do this.

I know that asking a question like this, people might advise me to
redesign my app. Well, as Raymond Chen once said about the Windows
batch "language" - this class was not designed, it has evolved... I've
neither the time nor the will to rewrite the whole thing; I'm just
trying to make it a bit more workable.

TIA!
 
P

puzzlecracker

Hi all,

There's a huge class in our app that I'd like to fragment a bit. I'd
like to move some of the code to a new class. The new class will have
to get a large number of parameters in order to do its job. As I see
it, there are 3 ways of setting that bunch of params:
- Pass them all as argument to one function
- Set each one of them
- Use a params struct
What bothers me is this: I'd really like to minimize the chance that
the caller will miss setting one of the params. The first way will
avoid that, but passing a large number of params to a function is
ugly. There might not be a better solution, but in case I'm missing
something, I'd like to know if there's any elegant way to do this.

I know that asking a question like this, people might advise me to
redesign my app. Well, as Raymond Chen once said about the Windows
batch "language" - this class was not designed, it has evolved... I've
neither the time nor the will to rewrite the whole thing; I'm just
trying to make it a bit more workable.

TIA!

gets/sets is the comment technique -- I would stick with it
 
K

khalid302

... that has a constructor to set all the members.

But then, values will have to be copied into the struct and then again
into the class.

I'd recommend using getters/setters the way they are implemented in
FLTK, for example, using parameter-based method overriding:

instance.varName (); /* returns the value */
instance.varName (value); /* sets the value */

As for checking if all the parameters are set, you should set default
values in the constructor, and before beginning to use the parameters
check if they have been set by the class's user.

Hope that helps
 
A

acehreli

But then, values will have to be copied into the struct and then again
into the class.

Not "have to" for two reasons:

- struct members may be references to existing objects

- the compiler may optimize away the copy
I'd recommend using getters/setters the way they are implemented in
FLTK, for example, using parameter-based method overriding:

instance.varName (); /* returns the value */
instance.varName (value); /* sets the value */

[This is not related to this topic, and completely subjective, but I
strongly recommend against using the same name for getters and
setters. It looks good on paper but very confusing.]

Now, what happened to the concern of copying? Wouldn't the setter copy
the value?
As for checking if all the parameters are set, you should set default
values in the constructor, and before beginning to use the parameters
check if they have been set by the class's user.

That method would first default construct and then assign. Since
assignment involves destructing and copying, I don't think you are
really concerned about the cost of the method I proposed. Maybe I
misunderstood you. Why did you object using a constructor to set the
parameters?

Additionally, you method requires that every member must be
assignable, which not every type are.
Hope that helps

Sure, but that is inferior to using a constructor. Besides, your
method does not address the OP's requirement at all: eran said "I'd
really like to minimize the chance that the caller will miss setting
one of the params."

Ali
 
I

Ian Collins

But then, values will have to be copied into the struct and then again
into the class.
Who copy? The class could work directly on the data.
I'd recommend using getters/setters the way they are implemented in
FLTK, for example, using parameter-based method overriding:
Which is always the sign of a bad design. How do you make sure they are
all called or which ones upset the state of the class?
 
T

tony_in_da_uk

... there are 3 ways of setting that [large] bunch of params:
- Pass them all as argument to one function
- Set each one of them
- Use a params struct
What bothers me is this: I'd really like to minimize the chance that
the caller will miss setting one of the params.
...

I'm also with the params struct w/ constructor approach, but just to
for a hoot I'll illustrate an alternative (pretty absurd) approach,
which successively changes the compiler's notion of type such that a
call only becomes possible when all parameters are set. ( Yes - enums
would have been better )

Cheers, Tony

// validate that all required parameters are supplied...

#include <iostream>

template <int flags = 0>
struct X
{
X<flags | 1>& a(int n) { a_ = n; return *(X<flags | 1>*)this; }
X<flags | 2>& b(int n) { b_ = n; return *(X<flags | 2>*)this; }
void do_something();

int a_;
int b_;
};

template <>
void X<3>::do_something() { std::cout << a_ << ' ' << b_ << '\n'; }

int main()
{
X<> x;
x.a(2).b(4).do_something();
x.b(2).a(4).do_something();
x.a(1).validate(); // won't compile...
}
 
E

eran

Thank you all for answering.

I'm afraid relying on setters does not solve the problem of omitting
the init of one of the params. Using default values and validation
might help, but not when using types like bool, in which true and
false are valid, and there could be no default value. Also, this
approach does the validation at run time. If possible, I'd like check
to be done at compile time.

After reading your suggestions and giving it some more thought, I had
a new idea, which combines all 3 options: Given that object copying is
not a problem (and it's really not, in this case), I could use a
parameters' class. That class will have several init functions,
divided by some sensible criteria, each initializing a different
subset of parameters. Making sure a few needed inits were called is
easier than making sure many setters were called, and the compiler
will make sure each call to any of the inits has been done with all
the right arguments. How does that sound?

Eran
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top