I referred to Bruce J. MacLennan’s Principles of Programming Languages in my previous post, then discovered I can’t find the list anywhere on the ‘net, at least not as I was taught them. They are (AFIK) derived from his book, also named Principles of Programming Languages, so it may not be precisely kosher to put them online, but I’m going to post a copy anyway, because they are terribly useful to refer to.
- Abstraction: Avoid requiring something to be stated more than once; factor out the recurring pattern.
- Automation: Automate mechanical, tedious, or error-prone activities.
- Defense in Depth: Have a series of defenses so that if an error is not caught by one, it will probably be caught by another.
- Elegance: Confine your attention ot designs that look good because they are good.
- Impossible Error: Making errors impossible to commit is preferable to detecting them after their commission.
- Information Hiding: The languages should permit modules designed so that (1) the user has all of the information needed ot use the module correctly, and nothing more, and (2) the implementer has all the information needed to implement the module correctly, and nothing more.
- Labeling: Avoid arbitrary sequences more than a few items long. Do not require the user to know the absolute position of an item in a list. Instead, associate a meaningful label with each item and allow the items to occur in any order.
- Localized Cost: users should pay only for what they use; avoid distributed costs.
- Manifest Interface: All interfaces should be apparent (manifest) in the syntax.
- Orthogonality: independent functions should be controlled by independent mechanisms.
- Portability: Avoid features or facilities that are dependent on a particular computer or a small class of computers.
- Preservation of Information: The languages should allow the representation of information that the user might know and that the compiler might need.
- Regularity: Regular rules, without exceptions, are easier to learn, use, describe, and implement.
- Responsible Design: Do not ask users what they want, find out what they need.
- Security: No program that violates the definition of the language, or its own intended structure, should escape detection.
- Simplicity: A language should be as simple as possible. There should be a minimum number of concepts, with simple rules for their combination.
- Structure: the static structure of the program should correspond in a simple way to the dynamic structure of the corresponding computations.
- Syntactic Consistency: Similar things should look similar, different things different.
- Zero-One-Infinity: The only reasonable numbers are zero, one, and infinity.
- Avoid Creeping Featurism: Do not add features which are expensive to implement and rarely used. [I think Rafi added this one himself, but I learned them from him, so here it stays. Also, I feel like there was a more elegant phrasing presented at some point.]
I’m not entirely fond of all the rules, particularly 6 and 7, which encourage trusting other people’s code and space inefficiency respectively, but it is generally a wonderful compact way of evaluating languages, that should resonate with anyone who programs.
Yesterday I decided to indulge my language fiddling impulse and spent some time reading about Vala and writing some simple programs in it. As far as I can tell, it is the answer to the running “My ideal language…” conversation my lab mate and I have, with only a few tiny exceptions. Even from a more formal view, evaluating based on Bruce MacLennan’s Principles of Programming Languages (not the book, just the list of aphorisms) Vala does INCREDIBLY well.
The syntax and feature set is based on C#, but instead of compiling to another unwanted virtual machine (Microsoft’s CLR or its second class citizen implementation, Mono), it compiles to (human readable) C, then native code, so it can piggyback on the platform CC. Most of the fancy language features are actually implemented with glib and GObject, so if you are running anything GTK based all the bits and pieces will be in memory anyway.
Rather than repeating the entire tutorial, the things I find exciting are: Array slicing. Proper Strings. Regular expressions. An optional garbage collector. A reasonable object system with limited inheritance and overloading. Coroutines(-ish) and iterators. Pointers of both the object-respecting and real varieties. Closures. Assertions/contract features. It also has incredibly clean interfaces for writing GUIs (in GTK) and network code, which are definitely weak points for most languages low-level enough for my tastes.
It does have a few interesting quirks (get and set methods allow you to override assignment, string concatenation is “+”, etc.), some dumb inherited things (were long and short ever a good idea?), and a handful of missing features (nothing has powerloops), but those are all minor quibbles.
The only real issues I have with Vala are that it isn’t terribly widely adopted, and that it is maintained by the GNOME foundation (which has a proud history of doing horrible things on a whim), but I think I’ll try writing all my random little bits of code in it for a while, because it is fun in a way I rarely find pure software.
We had a day of playing with Lisp in CS655 in preparation for the next assignment, and, like every time I am exposed to Lisp, it makes me think about one of my favorite ways of classifying programming languages. The dichotomy is is, as above, “Languages for computers” — Languages that directly manipulate the way computers tend to be actually implemented (Like C and FORTRAN, which have admittedly symbioticly pushed the design of modern computers) and “Languages for computation” — Languages built around a computational model (Like ML and Smalltalk). I’m a much bigger fan for the former.
Lisp sort of falls in-between. Lisp is definitely a “Lambda calculus with sugar” language in conception, but it has at various times actually made sense for the hardware it ran on. Initially, Lisp was implemented on the IBM 704; the CAR and CADR nomenclature for the head and tail of a list endemic to Lisp is derived from the way in which registers could be split and addressed on the 704, and is actually a fairly clever way of efficiently utilizing the available resources. This is also probably why Lisp is case insensitive; the 6-bit, Hollerith-card derived BCD character representation used on early IBM machines only had capital letters. Later on, mostly as a response to the AI communities’ love of writing computationally intensive programs in Lisp, which was (and continues to be) extraordinarily inefficient on most hardware, there were several generations of dedicated Lisp Machines, built with a bizarre tagged architecture specially suited to running Lisp code. These are now a well and truly dead breed, as they were expensive special-purpose machines of the kind almost completely eliminated by commodity hardware in the 90s, but did prove that it was possible (albeit expensive and ungainly) to make hardware that suited Lisp the same way most machines are suited to C and Fortran.
The remainder of this post is sort of an expansion of my griping about ML a few posts back, generalized to “computation” style languages. My first objection is partly personal; I’m much more interested in the way computers actually work, than the (admittedly alluring and elegant) field of computational theory, which frankly has very little bearing on the way computers work, and even less on the way they are used. This does lead to an argument that programs should be written to suit the prevailing hardware rather than the programmer, as they will be run many times but only written once, but that argument can be over-applied to any high level language, and can be mitigated by ever increasingly smart compliers. Another reason I don’t tend to take the “computation” type languages all that seriously is that I don’t really believe in attempting to formally verify programs. My observation is that programmers tend to be pretty good at writing what they mean (possibly excluding fringe cases) in any language they are comfortable with, but pretty bad at figuring out exactly what they intend to write, which is a validation problem, usually made worse by attempts at premature verification. There are a couple notable efforts to formally verify non-trivial programs, like se4l, but these conspicuously tend to be written in languages not designed to support formal verification. To the best of my knowledge there aren’t any formally verified programs large numbers of people actually use on a regular basis (it would be cool if there were; please correct me if there are examples, I’d love to see them).
I’ve been working on figuring out ML for an Advanced Programming Languages assignment. ML is a peculiar language, so it’s been taking some time, and when I’m spending hours staring at blocks of text I tend to get more into music as a complimentary activity. Both are turning up things worth sharing.
Functional programming has always confused me; as a computer engineer it strikes me as a deeply unnatural thing for the computer to do (what the hell does it look like in memory? — I mostly know and it isn’t pretty), and it isn’t a terribly natural paradigm for humans (although I will grant that is would likely be no more of a contortion for someone not accustomed to programming than any other paradigm). I guess there is a reason the deeply functional stuff tends to be mostly limited to “interesting” languages that are mostly outside the mainstream. I can “feel the power” on a lot of fronts; the ability to completely describe functions as input/output pairs is cool, recursion is natural and easy, and the type system is nifty, but it all still feels a little uncomfortable to me.
I’ve spent the last couple weeks on a Hyper Crush kick . Pandora brought me Hyper Crush off an A Kiss Could be Deadly derived station a while ago, and it took me a while to make up my mind about them. They make INCREDIBLY catchy, ostentatiously course, and somehow still incredibly geeky techno-influenced hiphop, which is either absolutely brilliant or unforgivably obnoxious. Aside from endless energy and spectacular synthesizer work, their songs are laced with a vast and remorseless collection of samples from and references to bits of pop-culture ephemera from the 1960s onward. Just to name a few, one track begins with a sample from The Shangri-Las “Leader of the Pack”, and another borrows its background from “Crazy Frog”. Both mixtape releases (Both available legitimately free online, but buried behind some flash obstructions) are shot through with samples from West Side Story, The Wizard, Back to the Future, and a wide swath of 80s and 90s video games. It is the pure sound of geeks letting their hair down, and it feels damn good.
To compliment the loud, I started listening to The xx yesterday, which I actually learned about from the music section in the back of last week’s The Week, which is usually too pretentious to pay attention to. Their debut album xx is unbelievably complex and nuanced for a first effort from a group of 20somethings. The lyrics are often male/female harmonies (I like the female vocalist’s voice much better, but thats par for the course with me), which are not necessarily the same words or timing for both voices but remain in harmony none the less. The lyrics are also quite subtle, one could reasonably make it through the entire album without realizing it’s mostly about sex. The coolest thing to me is how much they play with negative space; the crisp gaps are as much a part of the music as the instrumentation itself. There really isn’t any standout track, good or bad, on the album, so just go listen to any random track.
The latest weird obsolete piece of technology I’ve decided I enjoy is the Ada programming language, an older imperative language, developed at the request of the Department of Defense in the late 70s, and named after Augusta Ada King, Countess of Lovelace. The CS655 text Advanced Programming Language Design uses Ada-like syntax for its examples, so I invested a few minutes in reading some of the Ada Spec while working the first homework: its really a pretty cool language, especially the concurrency features that are actually integral to the language instead of half-baked in after the fact now that we’re rubbing up against the limits of single-thread CPU designs, and various compile-time and runtime self-checking features.
I’ve been exposed to an Ada-like language once before; VHDL, with which I’m fairly familiar, is derived from Ada’s syntax in the same way Verilog is derived from C. The advantages aren’t so obvious there; Verilog has a lot of the more idiomatic behavior cleaned out…and you can tear Verilog’s amazing array slicing features from my cold, dead hands.
I’m coming to appreciate that there are two distinct design philosophies in computing; incidental, haphazard, and/or organically grown designs which tend to become extremely quirky over time (ex: C, LaTeX, both of which I love dearly, largely for their quirks), which I will call “idiomatic designs” (the phrase is occasionally used elsewhere, not always for the same thing), and painstaking, careful “intentional designs” like Ada and that tend to be kind of unwieldy in real world applications. Unlike a lot of intentionally designed technologies, which tend to exhibit design-by-committee syndrome, the objection to Ada seems to be more because there was an attempt by the Department of Defense to mandate Ada for defense projects before it was fully mature, which bred considerable resentment, rather than any deficiencies in the language itself. I suspect Ada might actually make a comeback as a result of the elegant concurrency support, unless there is a miracle breakthrough in automatically parallelizing compilers in the near future. (I’d bet on the lack of usable generalized parallel programming models being the next big issue in computing.)
Probably more interesting than the dichotomy is the fact the organic approach is winning in most sectors. A lot. C and it’s various descendants are going strong; Ada is almost a dead language. UNIX is spreading; VMS is dying out.
In general, it seems like Idiomatic designs are idiomatic to suit themselves to what people actually use and enjoy using, even when they don’t objectively make sense.
Clearly I’m already learning useful things from CS655.
Side note: the best resource on C weirdness ever. It will hurt your head.