Why it’s great that Bitcoin is written in C++
C++ is a language many programmers find difficult to read and write in. As a software developer, writing Python comes smoothly to me. Even though I don’t particularly enjoy it, writing Go feels easy. Writing Lisp and Haskell are very entertaining, and almost enlightening. Not C++. You get an uneasy feeling. Even when your code compiles.
The first thing to note about C++ is that it is easy to shoot yourself in the foot. For example: have an unsigned integer as a command-line input? Inputting a negative integer will be parsed and evaluated as a massive unsigned integer.
One thing to note is that as you program more, a language becomes easier. I don’t think C++ is a terrible language. It just has a bigger learning curve, because of the multitude of programming paradigms it supports. Other languages are “easier” or “more elegant” mainly because they choose a single paradigm, or optimize around a group of problem domains and do it very well.
C++ as a multi-paradigm programming language supports single or mixed approaches using Procedural or Object-oriented programming and mixing in utilization of Generic and even Functional programming concepts.
Because Bitcoin is written in C++, maintainers are paranoid about new changes. Notably, paranoid doesn’t mean hostile or unwelcoming. Contributing to Bitcoin is quite the opposite! I recently submitted a code change that went through several rounds of prompt review, and some maintainers even directly reached out and thanked me for my contribution.
Contributing to Bitcoin
By default, changes are rejected unless there is a clear reason it is needed. Purely stylistic changes are rejected. This is quite surprising; the standard at established tech companies is usually the opposite. That people are grateful for those who jump in and update the style of old code.
Here we have an excerpt of a pull request that merely changed post-increment operators to pre-increment operators (something the style guide prefers) within consensus code. It was rejected.
Want to test a change? Compilation times are not great. Change 1 line of code and wait 25 seconds to compile just bitcoind, with all other intermediaries built (on a quad-core 16gb modern computer).
The upshot here is that when you want to contribute to Bitcoin, you need to be persistent. Your code will be scrutinized by several individuals, all of whom are doing this in self-interest tied to the success of Bitcoin. Peer review will be tedious. Another example is the very same user creating a pull request to change post-increment operators to pre-increment operators in a less critical code path. Greg Maxwell shoots this down because it makes no difference:
For each small comment someone leaves, and that you address in a commit, you need to wait 25 seconds for compilation, then 20 minutes for integration tests to run.
You need also need to be motivated. Skimming through the code, reading tests, tracing code paths, etc. takes time in a large C++ code-base; especially a code-base for a distributed system. The path to understanding enough about a complex system to make changes is long. Luckily, There are tons of amazing resources. I suggest Jimmy Song’s course, “Programming Blockchain”, and Andreas A.’s book “Mastering Bitcoin”. I am also extremely excited to check out “Programming Bitcoin” by Jimmy Song, since his class was so good. Perhaps the single most valuable resource in getting up to speed was pb-exercises, a git repository made for the Programming Blockchain class.
With all of this said, there’s nothing like digging through source code and slowly understanding things yourself. In order to really understand how things work, it is crucial to do both (reading high-level and isolated resources, and interacting directly with the codebase).
Compared to other Cryptocurrencies
One of the biggest critiques by prominent cryptocurrency businesses about Bitcoin is that it evolves slowly. For this reason, many of them rally behind a new favorite; be it Ethereum, Stellar, EOS, and others. Many of these cryptocurrencies choose Go as their language of implementation; and why not? It is blazing fast, easy to read and write. Ethereum’s most popular implementation is in Go (geth), and Stellar is written in Go.
Base Layer Evolution
Because of this, these languages evolve much faster. Ethereum is currently changing its entire consensus mechanism! Imagine — in Bitcoin, you get flack for trying to change x++ to ++x. Bitcoin can’t hope to keep up in evolving with other cryptocurrencies. The Bitcoin code-base is strictly relegated to being a replacement for container shipments of gold. I think investors should like this. Imagine making a massive investment in a cryptocurrency, only to have the leaders of it vote to change consensus to something new and experimental.
Even today, Satoshi Nakamoto’s simply math in modeling the difficulty of an attacker competing with an honest chain is relevant. We don’t need more complex modeling:
Second Layer Evolution
For this reason, I think the exciting developments in Bitcoin will involve second layer solutions. A potential solution is the Lightning Network. I say potential because it is completely experimental technology, that is not critical at all to Bitcoin’s success. As someone who buys into the “Bitcoin as digital gold” narrative, I like Lightning Because it opens up doors to better commerce and micro-payments; something Satoshi Nakamoto himself thought would be useful in an electronic currency.
Another interesting fact about Lightning Network is that an implementation of it is written in Go. The code is very easy to read!
This property of a supremely stable base layer, with less decentralized and more experimental second layer is more suited towards reality. We can optimize things on the second layer that are important, but not crucial to Bitcoin’s success as sound money.
For example, escrow protocols, fast transactions (LN), privacy, etc. can all be achieved on the second layer without compromising network security and stability.
It certainly may be annoying to developers at times to read and write C++ in a distributed networking application, when more domain-suitable languages are available. However, C++ forces developers to work slowly and deliberately. Second-layer solutions can evolve faster, given the social contract of the base-layer evolving slowly.