Writing Useful Code without Classes through the Lens of C Programming and Git
When I first started coding about 15 years ago, Python was the first language I started with. Python is a modern, higher level language that makes learning the ins and outs of coding very intuitive and accessible for beginners. Some of the basic building blocks of all programming languages include variables, operators, syntax, conditionals, loops, and functions. After learning these, most modern languages introduce the concept of the Class, usually relating it to the paradigm of Object Oriented Programming (OOP). In a nutshell, classes allow programmers to define representations of real world or business objects, and to interact with those objects via code. In fact, classes are so ubiquitous these days – especially in the dominant Model-View-Controller (MVC) paradigm that has taken web development by storm – that it can be hard to imagine coding without them.
However, there once were simpler times. Times when the concept of a class didn’t exist in the world’s available programming languages. One example of an old-school language that doesn’t have classes at all is C. It might seem logical to believe that in modern times, coding in a programming language without classes would be similar to farming with a shovel instead of a tractor. As C demonstrates, this is very much not the case. Functional programming has made a comeback in recent years, and languages like C are still updated, maintained, and heavily used despite their class-lessness.
So what, if any, features does C have instead of classes? Perhaps the most closely related one is the Struct. A struct is essentially a grouping of related variables that define a single object, and is similar to a very primitive class. Structs define a set of member variables (similar to class member attributes) that are lumped together into one object and stored contiguously in memory. Here is an example of a struct declaration in C:
typedef struct user user; /* Create an alias for `struct user` so we can just write `user` when declaring instances */
/* Define the `user` struct */
struct user {
int user_id;
char *first_name;
char middle_initial;
char *last_name;
};
An instance of the `user` struct can be initialized as follows:
user u = { 1, "Bob", 'M', "Smith" };
Struct instance member variables can be accessed with the dot operator as follows:
u.user_id
u.first_name
u.middle_initial
u.last_name
In contrast to modern classes, struct member variables in C are public, and there is no concept of member functions (or methods) which are central to working with modern day classes.
For these reasons, one might think that the development communities using these class-less languages constitute some sort of cult following combined with the stubborn sticklers who refuse to let go of their old ways. This is also not true. One prime example of a mainstream program that heavily relies on C (and by extension does not use classes in most of its code) is Git. Yes Git, the most popular version control system on the planet does not use classes in most of its code.
The primary reason for this is that Git’s creator, Linus Torvalds (also the creator of Linux) is a major proponent of efficient code that runs fast. He doesn’t care for the bells and whistles that modern programming languages offer in order to make the programmer’s life easier. He cares about good software design principles and optimal performance. Git’s current codebase is very large, but a good way to understand how Git’s code works without using classes is to take a look at the very first version of Git.
The original version is made up of only 10 files and a total of about ~1000 lines of code, and it actually works. (The fully documented codebase can be found here on BitBucket or direct downloaded here). Looking into these files, we can see that all the code exists in one of 4 scopes.
1) Global level code that runs when the file is imported/included
2) Code in the ‘main()’ function that runs when the file is executed from the command line
3) Code in functions that are called throughout the files and included in other files
4) Structs defined to represent the objects that Git works with, like caches and cache headers:
/* Template of the header structure that identifies a set of cache entries. */
struct cache_header {
/* Constant across all headers, to validate authenticity. */
unsigned int signature;
/* Stores the version of Git that created the cache. */
unsigned int version;
/* The number of cache entries in the cache. */
unsigned int entries;
/* The SHA1 hash that identifies the cache. */
unsigned char sha1[20];
};
/*
* Template of the cache entry structure that stores information about the
* corresponding user file in the working directory.
*/
struct cache_entry {
struct cache_time ctime; /* Time of file's last status change. */
struct cache_time mtime; /* Time of file's last modification. */
unsigned int st_dev; /* Device ID of device containing the file. */
/*
* The file serial number, which distinguishes this file from all
* other files on the same device.
*/
unsigned int st_ino;
/*
* Specifies the mode of the file. This includes information about the
* file type and permissions.
*/
unsigned int st_mode;
unsigned int st_uid; /* The user ID of the file’s owner. */
unsigned int st_gid; /* The group ID of the file. */
unsigned int st_size; /* The size of a regular file in bytes. */
unsigned char sha1[20]; /* The SHA1 hash of deflated blob object. */
unsigned short namelen; /* The filename or path length. */
unsigned char name[0]; /* The filename or path. */
};
Git’s fairly simple design is enough to build one of the powerful and popular development tools on the planet. It is a great example of a success story that isn’t based on fancy tools or complicated algorithms. It demonstrates that even old school tools can be the right choice for modern projects, depending on the requirements and goals. If you are interested in learning more about how Git’s code works, feel free to check out Initial Commit, which was created to help curious developers learn how their favorite tools are coded.
This article was written by Jacob Stopak, a software consultant and developer with passion for helping others improve their lives through code. Jacob is the creator of Initial Commit – https://initialcommit.io.
Let’s get in touch
Get a risk-free, no obligation proposal in 1 business day or less.