C++ Complementary Library
This page explains the reasoning behind the choices that were made in CCL.
C++ offers a vast array of benefits compared to other mainstream programming languages. Let's see what makes C++ a great choice for developing modern software in the 21st century.
You knew this was coming: C++ excels in terms of the kind of performance that it enables. Performance is of high importance for multiple reasons:
Computers are physical objects that perform work, and such thing consumes a non-zero amount of time and energy to successfully complete. If you consider work to be valuable, then the more work you can do per unit of time, the more value you can obtain.
We saw this with Doom, a revolutionary first-person shooter game. One of Doom's greatest qualities was that it provided an experience that was barely possible on the hardware that was available at the time it was released.
Another innovative accomplishment made possible by high performance is artificial intelligence. Neural networks make so many useful products a reality, but they only work in consumer products because there is sufficient processing power available in those devices. The more efficient the software, the more incredible features can be pulled off. This results in better products, and thus higher profits.
This should be reason enough to pay attention to performance. No one likes waiting for an app to load. No one likes waiting for tasks to finish. Slow apps are annoying and frustrating for users. Snappy apps that resspond quickly and don't make the user wait around are much more enjoyable to use. This results in better products, and thus higher profits.
If you doubt the value of performance, just remember that all else being equal, customers will choose the faster application. You can beat your competitor if your product is efficient and your competitor's product is not. This presents a very real opportunity because most applications made nowadays are not nearly as efficient as they could be.
C++ has a unique set of features that empower the programmer to embed real-world ideas in code. These features improve maintainability by allowing the programmer to shape the programming language according to the problem at hand, rather than forcing the programmer to shoehorn the problem into the ways of the programming language.
Let's get technical and see what these features are and how they are relevant to the daily craft of professional programmers.
With namespaces, you can use the best name for the situation without fear of that name clashing with software developed by other people. This takes away the constraint of coming up with a name that won't clash, allowing you to focus on the problem you are trying to solve.
For example, if you want to implement a class that represents
a vector as defined in mathematics, you can call it
vector
and just place it in a namespace
of your own. That way, it won't clash with the standard
library's vector
, which represents the
data structure.
If only there were a tool that would automatically find a large number of commonly made mistakes, for free, with the press of a button. I am, of course, talking about compilers of statically typed programming languages.
All kidding aside, static typing is incredibly useful because it catches mistakes that programmers using dynamically typed languages have to check for themselves. This kind of tedious work is often done by writing more unit tests, but it's so much easier to just let a tool do it.
In addition to facilitating better performance, static typing improves readability because it is a form of documentation. By being precise about the nature of your data, you are conveying intent to the reader of your code.
Let's say you are writing a function that needs to allocate an array of integers. What do you do if that allocation fails? Do you return an error code or set a reference argument to an error code? If several functions allocate memory and you account for every memory allocation failure with an error code, then you'll soon litter your codebase with error handling code. Not only that, but you often won't have a clean way out of the erroneous situation.
The truth is that you won't check for most of those errors because they are rare, they are... exceptional. If instead you allow the memory allocation routine to throw an exception, then all of a sudden your code becomes so much easier to read because now you don't have to handle the error at every step of your program. Instead, you write a try-catch statement and handle the error at the earliest point you can. If you don't write a try-catch statement, then your program will terminate, and that is better than continuing execution with corrupt data, which would probably lead to a crash anyway.
When an exception gets thrown, the objects that are on the stack are destroyed until you reach the earliest catch block, which guarantees that any resources you did acquire get properly released and cleaned up. Exceptions ensure that you either handle the failure at the earliest point you can, or your process will terminate, preventing further data corruption. This way, you know that you will either get correct behavior or graceful interruption. This is why exceptions are the correct answer to dealing with exceptional circumstances, and why error codes are not made for this kind of failure.
C++ lets you write code that does not depend on the types of its inputs, this is called generic programming. C++ does this with templates, and it is truly an amazing feature. Templates allow you to write generic classes, functions and objects. To use a generic function, for example, you instantiate the function template and that gives you a function that you can then use. The same applies for class templates and object templates.
Concepts allow you to constrain types. A concept is a set of requirements that types can be tested for. Templates and concepts together allow you to write code that only accepts inputs of types that match certain criteria. When you instantiate a function template, for example, the compiler checks to see if the types you supplied match the concepts that the function template specified (if any), and your code won't compile if the types you supplied are incompatible with the kinds of types that the template requires. And when compilation does fail, you will know the reason. This is so much richer than duck-typing.
Operator overloading allows you to assign new meaning to operators when they are used with objects of types that were made by a user of the programming language, rather than the creator of the programming language. This makes your code more expressive, as you can do things like multiply two matrices together with the multiplication operator, as opposed to calling a function explicitly. In addition to better aesthetics, operator overloading lets you say that a particular function represents a well-known operation, like multiplication in this example. This is an example of modeling power.
Operator overloading allows you to define the dereference operator and the arrow operator for your own classes, making it possible to make smart pointer classes that look and feel very much like the raw pointers that so many programmers are familiar with. Smart pointers are useful tools that make memory management much easier to deal with, and they do so with much better efficiency than a garbage collector.
This is going to be a short one. C++ is supported on a wide variety of operating systems and hardware architectures, and it runs on over 3 billion devices if you only count Java virtual machines.
When deciding on how a C++ codebase is going to be built, you have some options. These options include IDE projects, Makefiles, shell scripts and batch files. There's also CMake, which gives you a simple and uniform way of building cross-platform C++ code.
CCL uses CMake exclusively, and because CCL is made completely from scratch and has no third-party dependencies, you literally get the exact same experience building CCL on any of the supported operating systems. You don't have to install anything beyond a C++ compiler (which is a given) and CMake itself (which is easy enough to do), providing convenience and uniformity.
One of CCL's goals is to make sophisticated technology easily accessible, and that naturally led to the decision to use the Boost Software License. This license makes CCL free to use, even in commercial products. It also makes compliance easy because you don't even have to recreate the copyright notices and license information in your product's documentation. It's almost the same as public domain, in a way.
The Boost Software License makes CCL have a low barrier to entry. People will feel more encouraged to try it out and, if it's good, use it in the real world. Granted, CCL is still in Beta and has several known issues, but once CCL debuts its first stable release, this license will help CCL gain more adoption.
GitHub is widely known, works great, and makes it easy for people to sponsor the project thanks to the GitHub Sponsors program. There's not much more to say about this other than that GitHub provides a good experience and the GitHub Sponsors feature is a big deal for software projects that need funding to survive.
Copyright © 2022-2024 Daniel T. McGinnis