Two weeks ago today, I gave my CoffeeScript talk for the first time at a No Fluff Just Stuff tour event. Despite being received well both locally and at NFJS (sans one rather scathing review), I still feel like I’m not doing a good job explaining the difference between statements and expressions (on this point, I agree with the aforementioned negative review). In this blog post, I’ll sound-off my take on the difference in hopes that my followers can help me hone this into a solid and concise treatment. Bear in mind that my intended audience consists of programmers who have long been steeped in the tar pit of imperative programming. A lengthy excursion into formal lambda calculus is off the table, for instance, so I’m aiming for something colloquial. My goal is to nudge my audience’s thinking towards favoring expressions over statements, not to impress someone with big, college-education words.
What is a statement? In programming, this is an executable line of code. When you make a statement in a program, you are bidding the computer to do some action. In higher-level languages such as C, Java, JavaScript, etc., these typically translate down to several machine statements using assembly, bytecode, etc. Regardless of the compilation/translation process, these statements are intended to manipulate the state of the running program. Each statement changes a variable (hence a register and/or a value in memory), reads some input, or produces some output.
Expressions are a fundamental component of statements. Before a statement is executed, it must first determine the value which is to be involved. For instance, an assignment statement involves evaluating the expression on right-hand side of the operator before taking the action of assigning. Consider this trivial case of initializing a counter to zero: int i = 0
. The 0
on the right hand side is a trivial expression which cannot be reduced further. We of course can have more interesting assignments such as int seconds = 60 * 60 * 24
or even better, double area = 3.14 * r * r
. In these cases, the computer has a little work to do in order to reduce the expression down to a value, then perform the state change.
So what is an expression? It is a mathematical construct which can be reduced down to a simple value. Let’s not quibble about vocabulary here and focus on the last word: value. Expressions reduce to values. There is no notion of a program or state to manipulate. It can exist in a vacuum unlike a statement which requires this notion of program and state which can be manipulated.
Although CoffeeScript isn’t a purely expression-oriented language, it is more expression-oriented than it’s JavaScript counterpart. Let’s take a look at two if
/else
blocks of code which illustrate how we can replace statements with expressions. First, an if
/else
statement which sets min
to the minimum value between a
and b
.
if a < b min = a else min = b
Compare that to an if
/else
expression which sets the max.
max = if a > b then a else b
While both can be means to the same end, the latter shows us that if
/else
can just well be an expression, i.e. something which reduces to a value to which we assign the name max
. Imperative languages know that we need this expressiveness. Ever heard of the ternary operator?
max = a > b ? a : b;
Unfortunately the ternary operator is a superfluous special case which shouldn’t be needed. Many of the existing constructs in programming languages could be expressions. Take for instance, the switch statement (as Richard Minerich points out here for C#/F#). CoffeeScript lets it be a statement.
lunch = switch day when "Mon","Tue","Thr" then "salad" when "Wed" then "wings" when "Fri" then "happy hour" else "sandwich"
If this were JavaScript, I’d have to insert the same lunch =
text all in it. That is because if
/else
and switch
statements originate from a paradigm founded in thinking in terms of a computer which must move things, execute commands, branch, etc. Expressions on the other hand are founded in mathematics. if
/else
/switch
all translate well to mathematical functions, which are thoroughly studied and well-understood.
It turns out that expressions are generally easier to model logically and hence are more brain-friendly. This probably comes across as counter-intuitive to the masses who demand practical applications and scorn the rigors of mathematics. However, imperative programming is the result of years of dealing with the difficulties of the Von Neumann architecture by increasing abstractions. Expression-oriented programming (and hence functional programming) are the conclusion of decades of logical reasoning and deduction. Even for those who shy away from the abstract thinking involved in formal logic, it should be rather telling that these “practical” languages have a long history of striving towards abstraction, not away. The more I delve into programming with abstract expressions, the less I find myself in a mental battle to program. It flows much more naturally as it aligns with logical thought patterns.
Don’t buy it? Let’s also consider my previous statement about how expressions can exist in a vacuum. They have meaning without the context of the program. Statements on the other hand, do not. Sure, we can understand that a statement like println("Hello World!");
prints the obligatory first text to the console, but my point is that we include the notion of a program here. Expressions are simpler than statements because there are fewer components which are inherently involved. I would argue that simpler is always better. (See also, Simple Made Easy)
The more a language gives you expressions, the more you get to work with plain ol’ values, and the easier it is to reason about your code. While CoffeeScript offers mostly cute syntactic sugar, the strong gravitational pull towards more expressions is its greatest value proposition.
Leave a reply below, or send me a tweet.
