---
title: ((All Those Parens!))
description: S-expressions frequently help shape the first impression of functional languages as weird. Let's demystify them and reveal their benefits in this article.
image: https://blog.avenuecode.com/hubfs/Images/Blog/pexels-photo-38136.jpeg
---

[AvenueCode.com](https://avenuecode.com) [News](https://avenuecode.com/news) [Contact](https://avenuecode.com/contact)

[![Avenue Code Snippets Logo](https://blog.avenuecode.com/hubfs/Avenue%20Code%20New%20Logos%20-%202023/AC-Snippets---Black.png)](https://blog.avenuecode.com/?hsLang=en-us) *menu*

- Technology
  
  [Cloud](https://blog.avenuecode.com/blog/topic/cloud?hsLang=en-us) [Delivery Infrastructure](https://blog.avenuecode.com/blog/topic/delivery-infrastructure?hsLang=en-us) [Web Experience](https://blog.avenuecode.com/blog/topic/web-experience?hsLang=en-us) [Agile Mindset](https://blog.avenuecode.com/blog/topic/agile-mindset?hsLang=en-us) [Quality First](https://blog.avenuecode.com/blog/topic/quality-first?hsLang=en-us)
  
  [Design](https://blog.avenuecode.com/blog/topic/design?hsLang=en-us) [Solution Architecture](https://blog.avenuecode.com/blog/topic/solution-architecture?hsLang=en-us) [Data & ML](https://blog.avenuecode.com/blog/topic/data-and-machine-learning?hsLang=en-us) [Mobile Experience](https://blog.avenuecode.com/blog/topic/mobile-experience?hsLang=en-us)
- [Whitepapers](https://blog.avenuecode.com/blog/topic/whitepapers?hsLang=en-us)
- [Spotlight](https://blog.avenuecode.com/blog/topic/spotlight?hsLang=en-us)
- [Extraordinary Women in Tech](https://blog.avenuecode.com/blog/topic/extraordinary-women-in-tech?hsLang=en-us)
- [Avenue Code Culture](https://blog.avenuecode.com/blog/topic/avenue-code-culture?hsLang=en-us)

- [Cloud](https://blog.avenuecode.com/blog/topic/cloud?hsLang=en-us)
- [Design](https://blog.avenuecode.com/blog/topic/design?hsLang=en-us)
- [Delivery Infrastructure](https://blog.avenuecode.com/blog/topic/delivery-infrastructure?hsLang=en-us)
- [Solution Architecture](https://blog.avenuecode.com/blog/topic/solution-architecture?hsLang=en-us)
- [Web Experience](https://blog.avenuecode.com/blog/topic/web-experience?hsLang=en-us)
- [Data & ML](https://blog.avenuecode.com/blog/topic/data-and-machine-learning?hsLang=en-us)
- [Agile Mindset](https://blog.avenuecode.com/blog/topic/agile-mindset?hsLang=en-us)
- [Mobile Experience](https://blog.avenuecode.com/blog/topic/mobile-experience?hsLang=en-us)
- [Quality First](https://blog.avenuecode.com/blog/topic/quality-first?hsLang=en-us)
- [Whitepapers](https://blog.avenuecode.com/blog/topic/whitepapers?hsLang=en-us)
- [Spotlight](https://blog.avenuecode.com/blog/topic/spotlight?hsLang=en-us)
- [Extraordinary Women in Tech](https://blog.avenuecode.com/blog/topic/extraordinary-women-in-tech?hsLang=en-us)
- [Avenue Code Culture](https://blog.avenuecode.com/blog/topic/avenue-code-culture?hsLang=en-us)

# [((All Those Parens!))](https://blog.avenuecode.com/all-those-parens)

- [Tweet](https://twitter.com/share)

*perm\_identity* [Matheus Eduardo Machado Moreira](https://blog.avenuecode.com/all-those-parens/author/matheus-eduardo-machado-moreira?hsLang=en-us)

*schedule* 11/9/16 2:19 PM

> Functional programming paradigm and languages are usually associated with core features like **pure functions** and **immutable data (structures)**[1](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:1), and other properties like **referential transparency, higher-order (first order) functions, lazy evaluation**, and **recursion**[2](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:2). They arguably provide programmers with better tools and abstractions to deal with difficult actual problems that involve concurrency, parallelism, big data, etc.

Despite all those important characteristics, the most commom remark I hear about functional languages when talking about them with friends and co-workers is: "What a strange syntax! And look at all those parentheses, they must make the code very hard to read and write!" So let's try to demystify this "strange" syntax and see what benefits it can give to developers.

# **S-expressions**

The kind of "strange" syntax we are talking about is commonly associated with LISP[3](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:3) and derived languages. It is easily recognized by the usage of parenthesis to denote function call/application (together with **prefix notation**, in which the operator is placed before its operands) and as scope delimiters (instead of `{` and `}`, for example).

LISP uses a notation called **S-expression** (for Symbolic expression). It is a notation for **nested** list data and is used for source code as well as data representation[4](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:4). The authors of the excellent book *SICP* (*Structure and Interpretation of Computer Programs*)[5](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:5) introduce s-expressions in a simple way in section [1.1.1 Expressions](https://mitpress.mit.edu/sicp/full-text/book/book-Z-H-10.html#%_sec_1.1.1).

> Expressions representing numbers may be combined with an expression representing a primitive procedure (such as + or \*) to form a compound expression that represents the application of the procedure to those numbers. For example:
> 
> `(+ 137 349)`   
> *`486`*   
> `(- 1000 334)`   
> *`666`*   
> `(* 5 99)`   
> *`495`*   
> `(/ 10 5)`   
> *`2`*   
> `(+ 2.7 10)`   
> *`12.7`*

The authors call those expressions **combinations**. Combinations can accomodate procedures that may take an arbritary number of arguments, can be nested, and do not suffer from ambiguity:

`(+ 21 35 12 7)`   
*`75`*   
`(+ (* 3 5) (- 10 6))`   
*`19`*

Those characteristics are already an improvement over languages that use infix notation: it is not necessary to repeat the operator between operands (e.g. `21 + 35 + 12 + 7`) and to remember operator precedence (e.g. multiplication is evaluated before addition).

# **Homoiconicity**

Wikipedia defines **homoiconicity** (also know as *code-as-data*) as "a property of some programming languages in which the program structure is similar to its syntax, and therefore the program's internal representation can be inferred by reading the text's layout."[6](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:6) Put another way, a homoiconic language uses the same (*homo*) representations (*icons*) for source code and data structures.

Most languages need to read a program's textual representation and parse it into something that can be compiled and/or evaluated. This "something" is known as AST (Abstract Syntax Tree), a data structure that represents formally what is expressed in the source code. The following image is a sample syntax tree for the expression `requiresRole && userHasRole("MODIFY", assetId)`[7](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:7).

![syntax-tree-1.png](https://blog.avenuecode.com/hs-fs/hubfs/Images/Blog/syntax-tree-1.png?width=343&height=297&name=syntax-tree-1.png)

Most languages do not provide a straightforward way to manipulate the syntax tree - it is an internal representation only accessible to the compiler during compilation, for example. Homoiconic languages, on the other hand, have programs written using data structures that represent the syntax tree directly. The same `requiresRole`... code can be written as `(and requiresRole (userHasRole "MODIFY" assetId))`. Note how the code structure resembles the syntax tree.

## **Powerful metaprogramming**

Homoiconicity enables higher level metaprogramming facilities that cannot be attained by languages that do not exhibit this property. Higher level metaprogramming means higher level abstractions, which frequently translate to less code, more work done, and a lower margin for mistakes. Let's take a look at some interesting examples of what can be accomplished through this powerful feature. (The Clojure[8](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:8) language will be used in the examples, but the ideas and capabilities are shared among other LISP-like languages.)

### Java 5's enhanced `for` loop

Java 5 added a new syntax, know as **enhanced `for` loop**, to the language. It enabled developers to rewritte an "old style" `for` loop

```
for (int i = 0; i < collection.size(); i++) {
    SomeType element = (SomeType) collection.get(i);
    doSomething(element);
}
```

as

```
for (SomeType element : collection) {
    doSomething(element);
}
```

The new syntax is easier to read and write, and hides complexities (such as index manipulation). Java programmers had to wait until Java 5 to use the enhanced `for` loop because this addition required a change at the compiler level, and most programmers don't have the knowledge or ability to make it.

Clojure's metaprogramming workhorse is the **macro**[9](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:9). A macro is a special function that is executed during **compilation** and whose arguments are **unevaluated code**. The arguments are data structures that represent code! Given that `m` is a macro with a single parameter, the call `(m (+ 1 2 3))` will result in the parameter's value being `(+ 1 2 3)`[10](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:10), not the value `6`.

With macros a programmer could define in a few lines a `foreach`[11](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:11) construct, similar to Java 5's enhanced `for` loop, without touching the compiler or waiting years for it[12](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:12):

```
(defmacro foreach
  [[sym coll] & body]
  `(loop [coll# ~coll]
    (when-let [[~sym & xs#] (seq coll)]
      ~@body
      (recur xs#))))

(foreach [x [1 2 3]]
  (println x))
=> 1
=> 2
=> 3
```

### Code simplification

S-expressions sometimes make writing and reading chained function calls a bit cumbersome because we need to write and read the expression from the inside out:

```
(prn (conj (reverse [1 2 3]) 4))
; (4 3 2 1)
=> nil
```

In natural language we would say: "Reverse the vector `[1 2 3]`, append `4` to it and print the result. It would be nice if we could write code similar to what we just wrote in natural language:

```
(thread [1 2 3] reverse (conj 4) prn)
; (4 3 2 1)
=> nil
```

`thread` would be a form that passes the first value (`[1 2 3]`) through a series of method calls, passing the result of a previous call (e.g. `(reverse [1 2 3])`) as the first argument of the next call (e.g. `(conj [3 2 1] 4)`).

Clojure indeed has a macro that performs what was described: `->` (thread first). But the point here is that `->` is not a privileged language construct, it is a macro that we could have written ourselves:

```
(defmacro thread
  [x & forms]
  (loop [x x, forms forms]
    (if forms
      (let [form (first forms)
            threaded (if (seq? form)
                       (list* (first forms) x (next forms))
                       (list form x))]
        (recur threaded (next forms)))
      x)))
```

## **Final thoughts**

S-expressions, homoiconicity, and prefix notation are not weird characteristics of esoteric programming languages. They are well-thought out features that give rise to powerful tools at a programmer's disposal. With proper care, we are able to write code at a higher abstraction level, leading to less verbosity, more meaning (think DLSs[13](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:13)), more maintainability, and better code structure in general.

If you are interested in learning the functional programming paradigm, my humble recommendation is the *SICP* book. The authors use the Scheme programming language[14](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:14) and present the most important functional paradigm features and characteristics through several examples and exercises of increasing difficulty[15](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:15). Those who have an object-oriented background, particularly with Java, may find Scala[16](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fn:16) and Clojure very appealing.

1. ```
   (loop [coll3531 [1 2 3]]
     (when-let [[x & xs3534] (seq coll3531)]
       (println x)
       (recur xs3534)))
   ```

                      12. Clojure programmers do not need to define the foreach macro, since the language already has iteration facilities such as                                [doseq](https://clojuredocs.org/clojure.core/doseq). [↩](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fnref:12)                     

                       13. [https://www.gnu.org/software/mit-scheme/](https://www.gnu.org/software/mit-scheme/) [↩](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fnref:13)

                      14. There are a lot of references and resources about *SICP* online. Particularly useful are sites where it is possible to find                                         solutions for most of the exercises, sometimes with different implementations. But don't cheat! Try hard to solve the                                         exercises by yourself before searching for someone's else solution. It will pay off! [↩](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fnref:14)

                    15. [http://scala-lang.org/](http://scala-lang.org/) [↩](https://blog.avenuecode.com/all-those-parens/?hsLang=en-us#fnref:15)

---

[![LinkedIn Icon](https://blog.avenuecode.com/hubfs/Images/Blog/linkedin.png)](https://www.linkedin.com/in/matheusmoreira/)

### Author

# Matheus Eduardo Machado Moreira

 Matheus Eduardo Machado Moreira is a Senior Consultant at Avenue Code. He has 13+ years of experience with software development and has worked primarily with Java backend technologies. He loves his wife and family, likes to play games, and enjoys riding motorcycles.

---

### Related Posts

### Asymmetric Cryptography

[READ MORE](https://blog.avenuecode.com/asymmetric-cryptography?hsLang=en-us)

### Improving the developer experience when documenting

[READ MORE](https://blog.avenuecode.com/improving-the-developer-experience?hsLang=en-us)

### How to Run Rust from Python

[READ MORE](https://blog.avenuecode.com/how-to-run-rust-from-python?hsLang=en-us)

### How to Create a Tic-Tac-Toe Board Using React.js

[READ MORE](https://blog.avenuecode.com/how-to-create-a-tic-tac-toe-board-using-react.js?hsLang=en-us)

### Leave a Comment!

### Avenue Code Social

[![Facebook Icon](https://blog.avenuecode.com/hubfs/Images/Blog/facebook.png?t=1486470796564)](https://www.facebook.com/avenuecode)

[![Twitter Icon](https://blog.avenuecode.com/hubfs/Images/Blog/twitter.png?t=1486470796842)](https://twitter.com/AvenueCode)

[![LinkedIn Icon](https://blog.avenuecode.com/hubfs/Images/Blog/linkedin.png?t=1486470796556)](https://www.linkedin.com/company/avenue-code)

### Newsletter

Want to stay on top of all tips and news from Avenue Code?

### Popular Snippets

![ac-logo-inverted.svg](https://blog.avenuecode.com/hubfs/Images/Logos/ac-logo-inverted.svg "ac-logo-inverted.svg")

### About Us

- [Who We Are](https://www.avenuecode.com/who-we-are)
- [What We Do](https://www.avenuecode.com/what-we-do)
- [Portfolio](https://www.avenuecode.com/portfolio)
- [Partners](https://www.avenuecode.com/partners)
- [News](https://www.avenuecode.com/news)
- [Events](https://www.avenuecode.com/events)
- [Blog](https://blog.avenuecode.com/)
- [Contact](https://www.avenuecode.com/contact)

### Our Offices

San Francisco

[+1 415 766 4178](tel:+553125161448) [ac.inquiries@avenuecode.com](mailto:brazil.info@avenuecode.com)

Belo Horizonte

[+55 31 2516 1448](tel:+553125161448) [brazil.info@avenuecode.com](mailto:brazil.info@avenuecode.com)

São Paulo

[+55 11 3205 3232](tel:+553125161448) [brazil.info@avenuecode.com](mailto:brazil.info@avenuecode.com)

### We're Hiring!

- [Belo Horizonte](https://www.avenuecode.com/who-we-are)
- [New York](https://www.avenuecode.com/what-we-do)
- [San Francisco](https://www.avenuecode.com/portfolio)
- [São Paulo](https://www.avenuecode.com/partners)

---

©2015 - 2017 Avenue Code

[![Facebook Icon](https://blog.avenuecode.com/hubfs/Images/Icons/facebook-2.png)](https://www.facebook.com/avenuecode) [![Twitter Icon](https://blog.avenuecode.com/hubfs/Images/Icons/twitter-2.png)](https://twitter.com/AvenueCode) [![LinkedIn Icon](https://blog.avenuecode.com/hubfs/Images/Icons/linkedin-2.png)](https://www.linkedin.com/company/avenue-code) [![Glassdoor Icon](https://blog.avenuecode.com/hubfs/Images/Icons/glassdoor-icon-1.png)](https://www.glassdoor.com/Overview/Working-at-Avenue-Code-EI_IE456173.11,22.htm) [![YouTube Icon](https://blog.avenuecode.com/hubfs/Images/Icons/youtube-2.png)](https://www.youtube.com/user/AvenueCodePlay)

/\*\* DISQUS SCRIPTS \*\*/ Please enable JavaScript to view the [comments powered by Disqus.](http://disqus.com/?ref_noscript)

© 2026 Avenue Code

```json
{
  "@context" : "https://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Matheus Eduardo Machado Moreira",
    "url" : "https://blog.avenuecode.com/author/matheus-eduardo-machado-moreira"
  },
  "datePublished" : "2016-11-09T16:19:00.000Z",
  "headline" : "((All Those Parens!))",
  "image" : [ "https://blog.avenuecode.com/hubfs/Images/Blog/pexels-photo-38136.jpeg" ],
  "mainEntityOfPage" : {
    "@id" : "https://blog.avenuecode.com/all-those-parens",
    "@type" : "WebPage"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://blog.avenuecode.com/hubfs/Avenue%20Code%20New%20Logos%20-%202023/Avenue%20Code-primary%20versions_LOGO%20HORIZONTAL%20group%201-7.png"
    },
    "name" : "Avenue Code"
  }
}
```