I recently read a post by Peter Bourgon where he describes, with a set of examples and pictures, how contemporary art and architecture have transcended from being modern to post-modern. Let’s apply that distinction to contemporary programming languages. Can the current crop of programming languages be considered post-modern? I mean we have just begun. If current ones are post-modern, what will constitute as modern?

Then you might say — I can give you that answer, but care to tell the distinction between the two? So,

This is modern —

A building is a building is a building is a…

This is post-modern —

A building is also an eye

Isn’t it beautiful? Complex yet beautiful.

So, how can a programming language be complex yet beautiful?

Lately, I have been doing a lot of Go programming in my work and side projects. I started using it because there was a need. But it has since grown on me. Just like a post-modern art grows on you. Programming languages have long been meant to accomplish one (or may be a couple) things right and are designed precisely to do that. Some introduce functional concepts, some make it easier to use functional concepts, some are better at OO, while others at concurrent I/O, and so on. When was the last time you heard a language being designed for the sake of good design, inculcating best practices and making it easier to carry out complex tasks? This is what Go is about (other than just being a lexer+parser+compiler+linker that generates machine code). Sounds post-modern-y? Let’s observe a couple of samples —

Typing>

It is no coincidence that Go’s type system is borrowed from a language which is considered a pioneer of “complex ideas made simple” paradigm — PASCAL (1970). Much like it’s predecessor, Go is not stringent about declarations and the choice is left to every programmer’s own sense of style. So, all of the below are equally valid ways of declaring an unsigned integer type variable —

# var a uint32 # a := uint32(10) // or any other +ve 32 bit int # var(

# a uint32

# ) # type A uint32

# var a A

How they look at the crust might differ but underneath they all mean the same. Even this —

# type T uint32

# type A = T

# var a A

The last one is called ‘type aliasing’ in Go.

Every type conforms to an empty interface and any type conforms to a non-empty interface if it implements the methods defined on the said interface. This process is implicit. There is no ‘implements’ directive at work here.

The Go compiler places the program under a Duck Test, to know the conforming types. That is why sometimes this technique is referred to as ‘compile-time duck typing’.

These are layers in an art form that only a sophisticated observer (compiler in this case) can look at and understand and make sense. The details might miss the normal eye but that doesn’t diminish the quality of work that has gone in to result in something as intuitive and free-flowing as this.

Sharing>

The idea of shared mutable states is an old one. Every language on earth provide some way to access shared variables across multiple threads in a concurrent and safe manner. Go has a communication construct — channel— which is thread-safe by design, so can be freely read from or written to, from from any number of concurrent threads. A channel is generally used in conjunction with its owning goroutines which are the fundamental way of doing async programming in Go. This kind of multithreading is a variant of CSP-style state sharing, which was originally developed by C.A.R. Hoare in his seminal work from 1978. It doesn’t, though, imply Go has no support for traditional mutexes. It does. It has to. Sometimes it just makes more sense.

Other actor based languages like Erlang and Scala also support channels or some form of message passing. It just seems more at home here —

Queue a channel —

chan <- 1

Dequeue a channel —

<- chan

One or more channels can be shared across goroutines and still have different meaning to them. A programmer can then use this knowledge to create any number of senders/receivers (There are some gotchas while handling channels properly like buffered vs unbuffered, copy by value or pointer and such, but that’s a topic for another day).

The fundamental ideas of concurrency stay the same, and yet your program or rather the interpretation of a solution can look very different than mine.

When you come back from an art exhibition or an architecture tour, what remains with you is the form and feel of the depiction. It remains ingrained in you much as the traditional programming concepts are in today’s modern world of computing. They grow old, lose shape, but doesn’t come short of amazing you over and over again. That is the characteristic of a post-modern art. That is the characteristic of a post-modern programming language.

Thanks for reading.