Syntaxlessness
C-style languages invisibly impose a syntax, whereas Lisps do not. This makes Lisps more expressive and easier to grasp.
There is no such word as "syntaxlessness". We had to make it up to showcase that Lisps don't have a syntax.
You might be wondering, "But Shivek, we just studied Clojure's syntax in the last lesson, and now you say that Lisps don't have a syntax!?" We know that our statement sounds a little odd, but it will make sense by the end of this lesson.
In a C-family language like JavaScript, the following conditional is common:
if (a > b) {
console.log(a)
} else {
console.log(b)
}
The equivalent Clojure version of this conditional will look something like:
(if (> a b)
(prn a)
(prn b))
The if
function expects three elements in a list: the condition, the truthy block, and the falsy block.
Notice how if
and >
are just functions, unlike in C-style languages, where if
, else
and >
are a part of the syntax.
Expressiveness#
Since Clojure is a functional language and there is no syntax in the sense of C-style languages, Clojure code is more expressive and concise.
The example that we started with can be re-written as:
(prn (if (> a b) a b))
If your mind is arguing that this example is doctored and the C-style version can be written using the ternary operator, good! You are thinking along the right lines. The C-style version can be re-written as:
console.log(a > b ? a : b)
But there is a stark difference between the Clojure and C-style code (JavaScript in the case above). Can you spot it?
The ternary operator is a new piece of syntax whereas in Clojure code, only the order of function calls is changed. If JavaScript had the expressiveness of Lisps, the following code should have been valid:
console.log(if (a > b) a else b)
But it is not. The places at which the syntactical literals (elements that compose the syntax) can appear are limited in C-style languages.
The ternary operator is an escape hook. It is good enough for simple scenarios like the one above, but as our applications become more complex, the ternary becomes harder to manage. New syntax literals occupy mental share. Introducing new syntax hampers backward compatibility. Lisps however are free of syntactical issues, because no strict concept of syntax is enforced.
Since most famous languages are C-style, the idea of syntax is engraved in everyone's mind. This leads to code that is not as expressive as a Lisp.
Don't get us wrong here. Lisp is not always more expressive than C-style languages. It's only that Lisps enable the developers to write more concise code by not enforcing a syntax. As our programs become more complex, this property will become more evident.
Redefining core#
In Clojure, you can redefine if
to mean something else using the defn
function:
(defn if [condition truthy-block falsy-block]
)We don't know of a good reason to redefine if
, but it can be done.
There are however good reasons to redefine some other functions, for example, if you want a more efficient conj
for vectors.
This opens a gateway for third-party developers who can build faster implementations of common operations. For example, bsless/clj-fast is an alternate implementation for Clojure native data manipulation functions.
Conclusions#
There is no concept of syntax. There is only one hard rule that we learned in the last lesson - lists are function calls, and the first element of the list is the function that will be called.