An Interface is More than Names and Arguments

If you claim to conform to an interface, it is not enough to follow the syntax, you must also be careful about the semantics.

I saw an example of this the other day, when I came across a custom vector class (different from std::vector) used for numerics. It provided much of the same interface provided by std::vector, among which, resize().

It looked something like this:

template <class T>
class Vec {
  //! STL vector interface
  void resize(int size, T value);

That was however all the documentation that was available. Since it claimed to confirm to the stl::vector interface, I naturally assumed it meant the same thing.

Here is the documentation for std::vector::resize(size_type sz, T c):

If sz is smaller than the current vector size, the content is reduced to its first sz elements, the rest being dropped.

If sz is greater than the current vector size, the content is expanded by inserting at the end as many copies of c as needed to reach a size of sz elements.

Just to be sure, I had a look at the implementation of Vec::resize(int size, T value), and what do you know:

template <class T>
  //What was going on, conceptually:
  void Vec::resize(int size, T value) {
    _v.assign(size, value);

See the difference? Vec::resize() drops and initializes all elements, whereas vector::resize() only initializes any extra elements. This might be dangerous if you for instance port from Vec to vector and rely on all elements to be reinitialized by resize(), or if you port from vector to Vec and rely on resize() to keep your old values.

So when claiming to confirm to an interface, make sure to not only adhere to the signature, but also to the semantics.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s