Usergenic

Thoughts on humane software development

Dynamic Syntax

| Comments

I am a huge fan of the Lisp family of languages, but I do not frequently write in any of them with the exception of cobbling together elisp code for some simple buffer manipulations in emacs or embedding quick and dirty domain specific languages to provide portable glue code for different systems.

If I were to identify the major reason why I don’t generally like working in lisp, it would be the way it reads. It’s not that the language lacks the abstractions or features that make it possible to encode concepts or develop rich domain specific languages etc. To the contrary, Lisp may provide the greatest freedom of all programming languges to build abstractions for those things. So why do I not embrace it?

The problem for me is that it does all of these things without providing inherent means to escape the alien and somewhat inhumane aesthetic of prefix notation and endless nesting parentheses. This is unfortunate, because there is nothing inherently wrong with the underlying data structures or expressions conceptually. It comes down to readability.

Here is an example of the well-known quicksort algorithm. In my opinion, even with the indentation, Lisp’s homogenous and nesting list structures sort of blend together without visually offering any advice as to the weight or meaning of the code.

Quicksort in Lisp
1
2
3
4
5
6
7
8
9
(defun quicksort (alist)
  (if (null alist)
      nil
    (let* ((x (car alist))
           (xs (cdr alist))
           (fn (lambda (a) (< a x))))
      (append (quicksort (remove-if-not fn xs))
              (list x)
              (quicksort (remove-if fn xs))))))

Haskell is a language highly optimized for the expression of functions like quicksort, so its example reads more concisely and in so doing the behavior is somewhat more visibly apparent.

Quicksort in Haskell
1
2
3
4
quicksort [] = []
quicksort (x:xs) = quicksort small ++ (x : quicksort large)
  where small = [y | y <- xs, y <= x]
        large = [y | y <- xs, y > x]

Compare with the same algorithm in Ruby, from which you can pick the imperatives of the code even more readily.

Quicksort in Ruby
1
2
3
4
5
6
def quicksort(alist)
  return [] if alist.empty?
  x, *xs = alist
  less, more = xs.partition{|y| y < x}
  quicksort(less) + [x] + quicksort(more)
end

I bring this up about Lisp’s readability though, not to bash Lisp or compare it to other languages to show which is better but rather to simply demonstrate to what degree a language’s syntax and grammar can effect the speed of one’s ability to quickly understand the intent of code.

SQL is probably unparalleled in elegance in terms of being a domain specific language for performing arbitrary queries on relational databases. Implementing the same constructs in Ruby would seem a bit clunky. Consider this SQL that returns a list of users and the users who referrred them into the system:

Select users and their referrers in SQL
1
2
3
4
5
SELECT u.id, u.name, r.id, r.name
FROM users as u
LEFT JOIN users as r
ON u.referred_by = r.id
WHERE u.email='john@smith.com';

In Ruby, if you wanted a simliar embedded DSL (excluding the fact you’d probably be using an ORM like ActiveRecord or Datamapper) you’d need to do something like this, just to get along with Ruby’s syntax options:

Select users and their referrers in a Ruby DSL
1
2
3
4
db.select("u.id", "u.name", "r.id", "r.name").
from("u" => "users", "r" => "users").
join(["u","r"] => {"u.referred_by" => "r.id"}).
where("u.email" => "john@smith.com")

And the above example’s syntax wouldn’t support a percentage point of the various constructs available in SQL. The point here is that Ruby is a very readable language for general purpose imperative programming, but that doesn’t mean it is the most readable language when applied to every single domain. This especially true when compared directly to a domain-specific language like SQL.

I titled this post “Dynamic Syntax” because I’ve been thinking about what it could mean for application development if it were trivial to define new application-specific languages and syntaxes as a regular part of the development process. If it were possible at runtime to manipulate and extend the parser to allow syntax forms applying to select sections of code modeling different aspects of the domain, would people embrace this kind of development?

In some ways it doesn’t seem that different from writing a bunch of class methods and declarative-style code except that the end result could be much more intention revealing if the language were mapped directly onto the problem space.

In terms of inspiration, I have really enjoyed reading the source code to Inform text adventures (like this one) for the natural-language feel to their structure. I think there’s a lot of potential lurking in programming languages that promote this level of readability.

On the train on the way to work lately I’ve been toying around with nodejs/coffee-script and pegjs to experiment with writing a language that allows its own parser and VM to be altered as it goes. I’ll post my findings soon.

I am curious if anyone out there has opinions on the idea of higher degree of flexibility in programming languages.

syntax

Comments