Create your own
Lesson illustration

Expressions vs. Statements: A Language Comparison

Hello! Welcome to your first lesson on programming theory.

This course is designed to build a strong theoretical foundation for understanding programming languages and paradigms, moving beyond the practical application of specific languages like Python. As you requested, we'll explore functional programming, typing systems, and other core concepts, frequently referencing John C. Mitchell's "Concepts in Programming Languages" to ground our discussions.

We begin with Module 1, "Foundations of Functional Programming." The first step in understanding the functional paradigm is to grasp its most fundamental building block. This lesson addresses the following learning outcome:

Distinguish between expressions and statements, using examples from early imperative languages (e.g., C) and functional languages (e.g., Lisp).

This distinction is crucial because it represents a primary philosophical divide between imperative languages, which are built from commands that change the state of the computer, and functional languages, which are modeled on mathematical functions that transform data. Understanding this will be the bedrock for everything that follows, including concepts like purity and referential transparency.

Let's get started.

1. The Core Distinction: Expressions vs. Statements

At a high level, the difference is simple:

  • An expression is a piece of code that evaluates to a value. Think of 2 + 2, which evaluates to 4, or user.name, which evaluates to a string.
  • A statement is a piece of code that performs an action or causes a side effect. Think of an assignment like x = 5, a for loop, or a print command.

To get a more formal and historically-grounded perspective, please start by reading the definitions from John C. Mitchell's course slides.

Concepts in Programming Languages

These slides from 'Concepts in Programming Languages' by John C. Mitchell provide the formal definitions we'll use. We'll also look at how this distinction appeared in early imperative and functional languages.

Please read the following sections from the PDF: Go to slide 29, titled 'Basic Concepts', for the core definitions of 'Expression', 'Statement', and 'Declaration'. On that slide, under the heading 'Programming-language phrases – reminder', read phrase definitions. Briefly look at slides 32–35, starting with 'Part A: Imperative Languages', to see how an early imperative language, FORTRAN, was structured around statements. Beginning on slide 32, read FORTRAN overview. Finally, read slides 42–44, starting with 'LISP – LISt Processing', to see the contrasting philosophy of an early expression-based language. Beginning on slide 42 in the 'LISP: functions, recursion, and lists' topic, read LISP overview.

To deepen this understanding, let's look at a detailed explanation from a popular programming Q&A site.

language agnostic - Expression versus Statement

This Stack Overflow discussion provides an excellent, language-agnostic explanation of the distinction, its history, and how it has evolved.

Please read the top-voted answer by user Joel Spolsky. Focus on: The initial, clear definitions of expression and statement. The historical context using FORTRAN, where the distinction was very strict. How C began to blur the lines by allowing expressions to be used as statements and to have side effects. The summary of how functional languages like Lisp and ML largely eliminate the syntactic distinction.

2. The Imperative Tradition: Statement-Oriented Design

As you just read, early imperative languages like FORTRAN and ALGOL were built around statements. A program was a sequence of commands to be executed in order: do this, then do that, then change this variable. Expressions existed, but often only within statements (e.g., on the right side of an assignment).

C, which you have some familiarity with, inherits this tradition but, as noted in the Stack Overflow article, begins to blur the lines. Let's see this in practice.

C Programming Tutorial 9 - C Basics Part 1 - Variables, Expressions, Statements

This video, though introductory, provides a clear, practical demonstration of expressions and statements within the C language.

Please watch the following two segments from the 'C Programming Tutorial' by Caleb Curry: Understanding Expressions: About four and a half minutes into the video, watch expressions defined. Pay attention to how an expression is defined as anything that evaluates to a single value, like x / 2. Expressions and Statements Summary: Immediately after, at around six minutes in, watch expressions and statements. This part shows how an expression like x / 2 is part of a larger statement, int y = x / 2;. The semicolon at the end is what terminates the statement.

In C, the line is blurred in two key ways:

  1. Any expression can become a statement. You can write 5 + 10; as a line in a C program. It's a valid statement. The expression 5 + 10 is evaluated to 15, and the result is then discarded. It's a useless statement, but syntactically valid.
  2. Expressions can have side effects. The most common example is the assignment operator, =. In C, x = 5 is an expression that evaluates to the value 5. Its side effect is that the variable x is now assigned that value. This allows for code like y = (x = 5);, which assigns 5 to x and then assigns the result of that expression (which is 5) to y. This is a classic feature of C-family languages that is foreign to purely functional ones.

3. The Functional Tradition: Expression-Oriented Design

Functional languages, drawing their inspiration from mathematics (specifically lambda calculus), take a different approach. As you saw in the Mitchell slides on Lisp, these languages are expression-oriented. Almost everything is an expression that returns a value.

A program is not a sequence of commands to execute, but rather a single, large expression to be evaluated (which itself is composed of many smaller expressions).

Let's see how this works in Haskell, a modern, purely functional language.

Haskell for Imperative Programmers #2 - Functions, Types, let & where

This video, 'Haskell for Imperative Programmers', directly contrasts the functional and imperative ways of thinking about functions and values.

Please watch the following segments: Function Definitions and Expressions vs. Return Statements: Right from the start, watch function definitions. Notice the core idea: a Haskell function definition is an expression. There is no return statement; the value of the expression is the function's result. Let and Where Bindings as Expressions: A few minutes in, watch let/where bindings. This shows how even local variable bindings (let/where) are part of a larger expression structure, not separate statements.

The key insight here is that even control flow structures are expressions. Consider an if/else construct.

  • In a statement-oriented language like C or Python, it's a statement that directs control flow:

    // C code
    int y;
    if (x > 5) {
        y = 10; // statement
    } else {
        y = 20; // statement
    }
    

    The if block itself doesn't have a value; it contains statements that perform actions (assignment).

  • In an expression-oriented language like Haskell or Lisp, if/else is an expression that evaluates to a value:

    -- Haskell code
    let y = if x > 5 then 10 else 20
    

    Here, the entire if x > 5 then 10 else 20 construct is an expression that evaluates to either 10 or 20, and that resulting value is then bound to y.

This fundamental difference has profound implications. When everything is an expression that produces a value without side effects, reasoning about code becomes much more like reasoning about mathematical equations.

4. Summary and Key Takeaways

Let's consolidate what we've covered.

FeatureStatement-Oriented (e.g., C)Expression-Oriented (e.g., Lisp, Haskell)
Primary UnitA statement that performs an action.An expression that evaluates to a value.
PurposeTo issue commands and change state.To transform data and compute values.
Control Flowif, for, while are statements that direct execution.if, case are expressions that evaluate to a value.
Side EffectsCommon and central (e.g., assignment x=5 is a core operation).Avoided or isolated. Assignment is a binding, not a mutable action.
returnAn explicit return statement is needed to give a value back from a function.The function body is an expression; its value is implicitly returned.

This distinction is one of the most important concepts separating the imperative and functional paradigms. Your experience with Python places you in an interesting middle ground. Python is primarily imperative and statement-oriented, but it has adopted many functional features. For example, it has list comprehensions and a ternary if operator (value_if_true if condition else value_if_false), which are both expression-oriented constructs.


Conclusion

In this lesson, you learned to distinguish between expressions and statements, a foundational concept in programming language theory.

  • Expressions evaluate to a value.
  • Statements perform an action.
  • Imperative languages like C are built on a sequence of statements.
  • Functional languages like Lisp and Haskell are built on the evaluation of expressions.

This shift from "doing things" to "evaluating to a value" is the essence of the functional mindset.

Preview of the Next Lesson:
In our next session, we will explore referential transparency. This is a direct and powerful consequence of the expression-oriented, side-effect-free style of programming. You'll see how it allows us to reason about code as if it were a mathematical equation, a property that is difficult to achieve in statement-oriented languages.

Can't find a good explanation? Sign up and we'll make it for you

Sign up