Question Background
Consider a scenario in which I have two structs. Both consist of three fields for doubles. The only difference is the names used to refer to these fields. The first struct is for non-descript Tuples and the components are to be named x, y, and z. The second struct is for RGB values and the components are to be named red, green, and blue. Both of these structs need to have an interface defined for them such that operations such as vector/componentwise addition and scalar multiplication can be performed.
The Question
The problem? It seems terribly inelegant to copy and paste identical code for both of these structs only to change the naming scheme (x vs. red, y vs. green, z vs. blue). Ideally it would be possible in the interface function definitions to reference the fields of the struct (x or red) without having to name the field. Is this possible? If not then what other options are avaiable to me without changing the requirements? I include the struct definitions below along with some examples of their desired use with the possibly impossible interface I describe in this question.
Non-descript Tuple Struct
typedef struct
{
/** The first coordinate */
double x;
/** The second coordinate */
double y;
/** The third coordinate */
double z;
} Tuple;
RGB Tuple Struct
typedef struct
{
/** The first coordinate */
double red;
/** The second coordinate */
double green;
/** The third coordinate */
double blue;
} Tuple;
Example Usage
Tuple * genericTuple = createVector( 1, 2, 3 ); // create a generic Tuple
printf("%lf", genericTuple->x); // should print 1
Tuple * rgbTuple = createColor( 1, 2, 3 ); // create an rgbTuple
printf("%lf", rgbTuple->red); // should also print 1
Your types are in conflict
If you are trying to use your two different kinds of
Tuplein the same function, you aren't allowed to do that. It would fail to compile because the secondtypedefwould be in conflict with the first.For the sake of argument, lets say you are willing to give the two different types different names, but you want some code to somehow treat them as if they were the same type. One design pattern that allows this to happen would be the Adapter pattern.
Adaptor answers your question
Although you pose your question in the form of creating an interface, what you illustrated was two different interfaces, and you wanted both interfaces to work even when passed conflicting types. That would not be good software engineering practice.
Instead, what you should do to avoid "copy-and-paste" coding would be to figure out how to create or reuse common code that will work with your specific use case. This can either be through re-factoring commonalities from the specific cases, or by specializing a more general interface to your use case. Both can be achieved by applying Adapter.
I provide illustrations of the two directions of application below. However, keep in mind that they are merely illustrations, and that there are multiple ways to apply the pattern.
Adapt a
Tuplefrom a specific use caseSuppose you have a specific type to represent RGB values.
It is possible to create a
Tupleinterface to allow arbitrary use cases to be treated the same way. For example, we could use offsets.And you could then use it like this:
Adapt a specific use case from a
TupleSuppose instead you have a
Tupledefined like this.Then, you would have a print function that looked like this:
To use
Tuplefor your use case, you could defineRGBas so:And then you could use it like this: