Zachary W. Huang

Home Projects Blog Guides Resume

A breakdown of various programming language features

Disclaimer: I am not an expert on programming languages. This is just some stuff that I have encountered personally or thought about recently.


While the ability to const or final a variable exists in many programming languages, there is much more to immutability. In general, immutability allows you to safely refer to an existing value, since there is no chance it could get overwritten or dropped. Functional programming languages take this further with immutable data structures. Due to immutability, multiple data structures can refer to the same values in memory - copying values is unnecessary. When an immutable data structure is edited, only the element which was edited refers to a new value, and the rest is kept the same. Immutability is commonly used in conjunction with hashing, see git, nix, and unison. In these systems, each object is given its own unique name (a hash of it’s contents, usually), and these objects can then be referred to safely and unambiguously.

Languages: OCaml, F#, Haskell, Unison, (and available in almost every other language as a library)

Footnote: while immutable variables cannot change in value, many programming languages allow them to be “shadowed”, or overwritten by a different value of the same name in a local block of code. As a result, we can retain the concept of a variable which changes in value while still keeping the benefits of immutability.

First Class Functions

In languages with first class functions, functions can be manipulated and passed around just like any other value or object. For example, in Python, we can write square = lambda x: x * x, which results in a function square that will square any argument passed into it. The function can then be passed into another function such as map, which applies a given function to each element of an iterable. We can do: map(square, [1, 2, 3]), which will return [1, 4, 9]. In languages such as C and C++, function pointers can be passed around, but they are not first-class values.

In addition, first class functions come with closures. Typically, functions can refer to variables outside of their scope. But what if a function that refers to a variable is passed into another function and evaluated in a different scope? Well, it still needs access to the originally referenced variable. The original function must therefore “close over” variables it refers to, even if it is actually called in a different scope. I talk about this a little more in my blog post Functions are all you need.

Languages: Python, Lisp, Javascript, OCaml, etc (basically all scripting or functional languages)

Lazy Evaluation

In a lazily-evaluated language (aka call-by-need), expressions are not evaluated until they are actually needed, such as if they are to be printed to the screen. Instead of passing around values, we are actually passing around pinkie-promises (called thunks) that an expression will eventually evaluate to something, but only when we need it. When lists are also lazily evaluated, we can manipulate and pass around infinitely-long lists while only using a finite amount of memory. This is because instead of holding an infinitely-long list in memory, we simply hold the first element along with a thunk which will evaluate to the rest of the list.

Languages: Haskell, Nix, available to almost every other language as a library

Sidenote: Lazy evaluation can be added into a language using first-class functions. We can easily wrap an expression in an anonymous function to delay it’s execution, thereby creating a thunk - we can then pass this function around instead of a value.





RSS icon github logo linkedin logo

Zachary W. Huang © 2021-2024