{{< Concepts >}} {{< Unsafe reason="These are the approximate steps to do it safely, but we haven't made each be error-detecting." >}}
- Unknown.
class Applesauce {
};
- Overload the method under refactor with a new method. The new one has same signature and directly calls the method under refactor. This will be the wrapper method, which will enable existing callers keep working unchanged while you refactor. It will be inlined later in the recipe.
// Method under refactor
bool drawCircle(const int x, const int y, const int radius)
{
// implementation
}
// Wrapper method
bool drawCircle(const int x, const int y, const int radius)
{
return drawCircle(x, y, radius);
}
- In your wrapper method, right before the call, create a new instance of your empty class and store it in a variable.
// Wrapper method
bool drawCircle(const int x, const int y, const int radius)
{
Applesauce a;
return drawCircle(x, y, radius);
}
- Add new parameter of type
Applesauce
to the method under refactor, and pass in the variable.
// Method under refactor
bool drawCircle(const Applesauce& a, const int x, const int y, const int radius)
{
// implementation
}
// Wrapper method
bool drawCircle(const int x, const int y, const int radius)
{
Applesauce a;
return drawCircle(a, x, y, radius);
}
- Compile and check in.
Do not use "= default" instead of the empty braces {}, because you will be adding parameters to this constructor in the next step.
class Applesauce {
public:
Applesauce()
{}
};
For each parameter:
- Add the parameter received into the wrapper to the end of the constructor call for the new class.
// Wrapper method
bool drawCircle(const int x, const int y, const int radius)
{
Applesauce a(x); // <-- right here
return drawCircle(a, x, y, radius);
}
- Add the argument to the constructor. Copy and paste the type signature from the wrapper method.
class Applesauce {
public:
Applesauce(const int x)
{}
};
- Add a public field to the class. Paste the same type signature again. Remove any
const
orvolatile
(not sure what you should do if you have volatile params). Prependm_
to the variable name if that is in your style guide.
class Applesauce {
public:
Applesauce(const int x)
{}
int m_x; // <-- right here
};
- Initialize the field from the constructor arg.
class Applesauce {
public:
Applesauce(const int x)
: m_x(x) // <-- right here
{}
int m_x;
};
- Compile and check in
5. Working in the method under refactor, change one argument at a time to use the value on the field.
For each argument:
- Find every read or write for the param and replace it with a read or write for the same-named field on the new object. You can use the compiler to find them by commenting out the parameter declaration, but not any variable declaration in the function that shadows the parameter.
// Method under refactor
bool drawCircle(const Applesauce& a, const int x, const int y, const int radius)
{
HorribleGraphicsAPI.drawCircle(a.x /* right here */, y, radius);
return HorribleGraphicsAPI.HadError();
}
- Compile and check in
- Remove unused parameter from method declaration.
- Remove unused parameter from the method call in your wrapper method.
// Wrapper method
bool drawCircle(const int x, const int y, const int radius)
{
Applesauce a(x);
return drawCircle(a, y, radius); // <-- 'x' is no longer here
}
- Compile and check in
- Update one caller at a time; check in after each one.
- Remove the wrapper method. Check in.
- No default-valued parameters. If you have these, pass the default in at all call sites, or make an overload that doesn't have them.
- Non-constraint: You don't have to take all the parameters. Any continuous subset will do.
Given:
A F(B b, const C& c, D& d)
{
cout << b;
}
F(b, c, d);
- At the function declaration, copy the parameter list and paste it in to a new struct. replace commas with semicolons and add another semicolon at the end of the list.
struct F_Params
{
B b;
const C& c;
D& d;
};
- Change the function signature to take the params object, by value
F(F_Params params)
- and fix up all uses of parameters to use this object:
{
cout << params.b;
}
- Add braces at the call sites:
F({b, c, d});
Next steps:
- You'll probably want to follow up with removing the '&' on the fields, making copies of the parameters. Not guaranteed safe.
- Remove const from the fields.