Programming with no rules
A type system in a programming language provides rules and restrictions. They tell you all sorts of things that you can’t do. Ever find yourself jumping through hoops just to satisfy the compiler’s stupid rules? It’s even worse with functional programming, where you can never change the value of a variable after “setting” it. What’s the point of rules except to get in the way?
They give you a path:
When driving to work, you don’t complain that you’re restricted to drive only on the roads. Driving down the road makes easier to navigate. If you were to drive arbitrarily through gardens and parks and shopping malls, apart from wrecking your car you would also find it much harder to navigate. Normally you only have to consider which way to turn when you get to a junction, but now everywhere is a junction! Everywhere is a new choice.
They make it easy:
If society were to abandon roads because they restrict your driving too much, then where would we put the tar to make driving more pleasant? In other words, the more restricted we are about what we’re allowed to do, the better we can work on and improve those few things that we allow.
There are two points to this. The one is that if you have tons of options at each decision in making a program, then to describe one of those options is more difficult. This is simple information theory: the more “expected” something is, the easier it is to represent. The less information you need to convey, the easier it is to say it.
The other point is simply related to the work involved in giving you all the options. It’s easier to make road-cars and roads than to either make all cars capable of driving over anything, or to simply tar everywhere. In other words it takes time and money to implement language features, and time and effort to learn to use them. Although it’s theoretically possible to just tar everything, the resources involved would better be spent on making the existing roads more pleasant and safe to drive on.
They come with some guarantees
The rule that people must drive on the road comes with some great advantages that we all know and love. For example, I don’t need to do my gardening with the expectation that people might drive through it [1]. I don’t need to wear a helmet in the mall. If I better know what to expect from the behavior of a car, then it makes it easier to plan my own behavior and easier to do things in general.
In other words, even though rules can restrict one entity, they really help when it comes to cooperation between multiple entities. And cooperation is the key to making big programs. I’m not talking about cooperation between programmers, I’m talking about cooperation between parts of a program. The more well defined the rules of the game (language and interface specifications), the more the players can play instead of worrying about what others do or don’t do.
If I had to program with no rules, it would only be easy for the very first piece of code. The second piece I would now have my first unruly piece of unpredictable code to interact with, and so I’d have to put on a helmet and tons of error checking.
But what if we just have the best of both worlds? What if we say there are just “guidelines” – you get all the benefits of the rules, except you can bypass them in the case where you have good reason to do so?
Just guidelines
Sounds like a good idea [2]. Now you can drive on the road most of the time, because it’ll give you all the benefits of the rules, but you can turn into a park if you need to get to the other side and it’s too far to go around. We advise you not to cast an int
to a std::string
, but the referee won’t blow the whistle if you decide that’s what you want [3] [4].
But wait, what about me? Do I need to wear a helmet when I’m potting my pretty petunias or not? I’d better call up every single person who lives in the area to see if they plan on driving today.
In short, guidelines are stupid when it comes to cultivating cooperation [5]. There should be a well-defined set of rules, which the compiler/referee/traffic officer will enforce, that tell you exactly what behavior you can expect from another part of the program. If a function has a return type of a string
, you should be damn sure it’s not returning an integer, otherwise there’s no point in playing anymore and I give up!
Public Safety
The metaphors intersect when it comes to security and safety critical applications. The traffic lights are running software, the ATM is running software, paypal is running software, the x-ray machine is running software. In a C/C++ world, where there are only guidelines, and where you can make a call to a string instead of a function, and free a banana instead of a pointer, there is no such thing as guaranteed security. C programs can’t even guarantee that they won’t do something terrible when there isn’t malicious intent. Keeping your password as a “private” unused field doesn’t mean it can’t accidentally be sent to mars, and keeping it “const” doesn’t mean it can’t accidentally be changed. Not assigning to the x-ray-strength
variable doesn’t mean it won’t change “on its own” because of some crazy pointer mistake in an unrelated part of the system. No piece of C/C++ code comes with any guarantees when it’s integrated with other code. Instead of commenting functions with what they do, they should all be commented with “this function really does anything, but what I hope it does most of the time is this…”
Conclusion
I do exaggerate a little [6]. But the point is clear: rules offer more advantages than guidelines when it comes to making and interacting with predictable software. Because of its roots in math, software is one of the few (perhaps the only) engineering disciplines where it’s actually possible to completely and perfectly guarantee behavior. And it’s even easier to guarantee the lack of certain unwanted behaviors (eg using strings as integers, or accessing memory you don’t permission to). This is not a “guarantee” in the legal sense, where you get your money back if it’s wrong. This is a guarantee in the mathematical sense, where there is no such thing as wrong. I think we need to use this to our advantage. Seriously.
To anyone who feels comfortable in C or C++ I say, you need to set your standards higher! There is another world on the other side where there is no such thing as segfault or a heap corruption! There is a place where you can tell what a function doesn’t do just by looking at it’s signature! Come and join me!
[1] I don’t actually have a garden. What a shame
[2] Sure, I’ll play along
[3] string s = (string&)x
[4] It’s ok, because I’ll remember to only call it with an int that’s actually a string so I won’t kill any puppies
[5] Guidelines are still good for communication between cooperating individuals, but they can’t be trusted like rules can
[6] Just a little