In my experiences, I often see some design patterns such as visitor patterns, strategy pattern, in object-oriented languages like Java. But I haven't seen much patterns in procedural languages like C.
Do those patterns exist in procedural languages?
Procedural languages indeed have design patterns. But since the procedural approach is generally neglected in favor of the class based OOP, they are not widely recognized.
I develop high performance software in C, and there are several recurring patterns. So I'll provide some insight what patterns I see often.
Handles
This is how encapsulation is done in procedural programming. The constructing function doesn't return a struct or an object. But a handle: it's generally an opaque pointer or just an integer. You cannot do absolutely nothing interesting with it because it's just a number. The details are completely hidden. But you can pass this handle to the functions that deal with it:
Examples:
Contexts
Objects are usually called contexts in procedural language. Context is a struct that contains the state of some system, just like the members of an object. In OOP you write object.method(parameter)
. In procedural programming you write function(addressOfContext, parameter)
. The internal functions use the context structure directly, while public functions take a handle only and the implementation resolves it to the actual context structure.
Callbacks
Or function pointers. The user of the function passes the address of his function to add custom behavior to a system. This how polymorphism is done in procedural programming. This allows writing generic functions.
A notable example of this is the qsort C function. This takes the address of an array of elements. Takes how large one element is and how many elements in the array and a comparator function which performs the comparison. That's completely generic implementation and allows sorting all kinds of data.
Setup structs
When a function can be parameterized in lots of ways. Typically a setup structure is used. Specifications often require that these structs are zero filled by default, and only the relevant members are filled. If some members are mutually exclusive they are placed in an union. Typical example of such setup struct is the WNDCLASS from WinAPI.
Variable size data
Well this is rather a C pattern than a general design pattern. Sometimes objects may hold an arbitrary size binary payload. This pattern typically occur when reading data from binary files than can contain several types of data chunks. That's done by a struct like this.
typedef struct
{
int someData;
int otherData;
int nPayloadLength;
unsigned char payload[1];
} VariableSized;
And in the code the following is done:
VariableSized *vs = malloc(sizeof(VariableSized) + extraLength);
This allocates memory thats larger than the struct allowing space for a variable length payload. Whose 5th byte then can be accessed by eg. vs->payload[4]
.
The advantage of this that the whole object can be freed in one free
call. And it's guaranteed that it have a continous block in the memory. So it utilizes the cache better than allocating the corresponding buffer somewhere else in the heap.
Procedural counterparts of OOP design patterns
OOP patterns are never called in their names in procedural languages. So I can only guess here.
Creation patterns
if (!initialized) { initialize(); initialized = 1; }
pattern at places that are not performance critical. For performance critical code, lazy loading is not used at all. The user must find a place to initialize the context.Structural patterns
Behavioral patterns
do
and undo
callback. These callbacks usually take some kind of context to operate on. And array of commands are maintained to perform the undo.malloc
and free
.The book "Design Patterns: Elements of Reusable Object-Oriented Software" was a landmark book that brought attention to Design Patterns in the practice of computer programming, design and architecture.
The dominant programming paradigm at the time was Object-Oriented software development, and the book was clearly targeted to that paradigm, and not to others. Although you could argue that some design patterns in the book applied to other paradigms, it wasn't the focus of the book. So what has become popular with designers and programmers was the set of design patterns outlined in that book.
Since then, others have been documented by other authors, bloggers, and other websites.
No doubt that there are design patterns that apply to procedural languages that have been described on various websites. However, like I said, when the programming community speaks of design patterns, they are mostly referring to the patterns outlined in that book.
I know this is not a real answer because I don't know where any documented patterns are for procedural languages, there certainly are some, I'm sure. I thought maybe I'd state the importance of that book, and the paradigm it was originally targeted to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With