I’m writing a linear algebra library (long story short, it’s a school assignment) that involves matrices, vectors, etc. In the process of creating this library, I’m going to be creating functions that perform mathematical operations on objects. For example, transpose matrix, invert matrix, normalize vector, etc.
I was curious as to what is the “best practice” for this sort of function… That is, should I make the function a member function, or non-member? (For clarity/library use sake)
Example:
//Member function way:
B = A.transpose();
C = A.inverse();
//Non-member function way:
B = linalg::transpose(A); //Non-member transpose function in linear algebra namespace
C = linalg::inverse(A);
Is there some standard regarding these sorts of operations? Or, at least, is there a common way people do this? I’m leaning towards the first option, but I’d like to know if this is recommended.
This is just a matter of style and taste. I have seen different linear algebra libraries, either
-
written in an OOP style using member functions
-
written in a non-OOP style using only free functions
-
providing an API with both
and all of them were working. At least, your API should be consistent, so pick your choice and make sure you don’t mix those styles arbitrarily.
Avoid membership fees: Where possible, prefer making functions
nonmember nonfriends.Nonmember nonfriend functions improve encapsulation by minimizing
dependencies: The body of the function cannot come to depend on the
nonpublic members of the class (see Item 11). They also break apart
monolithic classes to liberate separable functionality, further
reducing coupling (see Item 33). They improve genericity, because it’s
hard to write templates that don’t know whether or not an operation is
a member for a given type […]
Herb Sutter
1
Both member and non-member functions have real advantages besides mere taste. For example, the underlying array(s) used to implement a matrix
class will probably be private
, therefore, you will have to use friend
unless you use member functions. In this respect, an OO design may be better.
However, keep in mind that, from time to time, computer scientists have to implement complex math formula without always knowing what thy really do. When I have to do so, I prefere non-member functions since the “visual” result will be closer to the original math formula (since math formula generally use a functional style).
In the end, the answer is the same as Doc Brown’s one: it’s a matter of taste. In short, you could consider writing an OO-style library with member functions (easier to write, no friend
), then writing non-member functions to do the same tasks which will simply forward their arguments to the member ones. It allows you to be consistent and to let the user choose what he thinks is best.
If you dive deeper in your problem statement, it is clear that at some point you’ll use custom data structures that represent certain mathematical entities. For instance, you might represent a matrix my means of a n-dimensional array. To elaborate on your example,
// C way
typedef struct {
int data[MAX_LEN][MAX_LEN];
} MATRIX;
MATRIX B = transpose(A);
// C++ way
class Matrix; // Forward Declaration
class Matrix {
int data[MAX_LEN][MAX_LEN];
public:
Matrix transpose();
};
Matrix B = A.transpose();
(The C++ example is simplified, you can use templates and such.)
The point to consider is the ease of using custom data structures in both cases. C++ (or any object oriented) as a language is more powerful in itself, and that extends to the consumer of the library as much as it benefits the implementer.
I’ve used C only libraries in the past and those custom data structures seem to get all over the place in no time! Whereas interoperability is easier to achieve with the latter (using special constructors, maybe?)
To wind it up, if you’re using C++ then a object oriented approach is definitely recommended.
2