It was quite hard to put what I meant into a title, but it’s easy to put into code.
C++
Is this
int offset_x = 10;
int offset_y = 40;
...
element.move(offset_x, offset_y);
To be preferred over this?
Vector<int> offset(10, 40);
...
element.move(offset.x, offset.y);
(Note that Vector is not like std::vector
, it’s a 2D vector. This class has lots of methods I don’t need here, like normalize()
and scale()
. Should I have a more basic Point
class for this?)
JavaScript
Is this
var offsetX = 10;
var offsetY = 40;
...
element.move(offsetX, offsetY);
To be preferred over this?
var offset = {x: 10, y: 40};
...
element.move(offset.x, offset.y);
I have “inherited” a lot of legacy code using your first variant, and also written lots of code by myself using Point2D
and Point3D
classes instead (essentially the same what your Vector<int>
is about). The first variant leads always to functions with too many parameters and too many repeated constructs where simple vector addition or scalar multiplication is repeated again and again in several lines of code.
Using 2D point or vector classes, however, especially when you have the need for a lot of vector operations, makes the code much cleaner, concise, better readable and maintainable. If you should use an existing Vector<int>
, or write your own Point
class instead is impossible to say without knowing more about the details of your code, but in general, if an existing class suffers your need, why not reuse it? The additional methods you don’t need typical don’t hurt. But not using any 2D point/vector class is almost everytime the wrong decision. And in your example above: if you have influence on the element.move
function, IMHO you are better off to design it in a way you can call element.move(offset)
instead of element.move(offset_x, offset_y)
.
For example, say you need an array of point coordinates, and you are going to use a std::vector
. In the first case, you will need two std::vector<int>
variables, you have to make sure those two vector are “in sync” with each other, and all adding of new elements, finding existing elements, passing around of those elements needs two lines of code instead of one when you had choosen to use a std::vector<Point2D>
instead.
To give a more general answer, variables should be grouped into an object when it makes logical sense to do so.
- Are the variables different aspects or properties of one “thing”?
- Do they always belong together?
- Will they be used enough to justify any extra work that may be involved in creating an object?
In your case, I would say that your code clearly improves when you group the variables together.
But if variables are slapped together in an object that is not well thought out, you can be stuck with an unwieldy design that is worse than using normal variables.
Conversely, it is possible to over-design: spending too much time thinking about and building the “perfect” object-oriented structure, to the point that it stops you from actually getting things done.
Actually, I think the best way is to do this:
Vector<int> offset(10, 40);
element.moveBy(offset);
This code abstracts away the dimensionality of your vectors, and the same line of code (element.moveBy(offset)
) will work unchanged if you change your vectors to 3D, or doubles, or even polar coordinates, as long as your types implement the required operations correctly.
For example, consider the following code:
Vec wallBounce(Obj& o, cont Wall& w) {
assert(isUnit(w.normal));
Vec perp = dot(w.normal, o.velocity) * w.normal;
o.velocity -= 2 * perp;
}
Anyone with enough vector math clue will understand what happens here; additionally, the function is short, to the point. You can’t see what Vec
is typedef’d to, but that’s usually not very interesting and also trivial to look up; the code clarity and brevity more than make up for it. After all, coding is all about making abstractions, and abstracting groups of scalars into vectors is a very powerful abstraction. For kicks, try and implement the above function without making this abstractions, for 2D vectors, 3D vectors, and scalars.