I got Bruce Tate's "Seven Languages in Seven Weeks: A Pragmatic Guide to Learning Programming Languages" book ages ago, but like with all books which require significant active effort it gathered dust on my bookshelf for quite some time. Now that I've read it and did all the recommended exercises I must say it's absolutely awesome!
The book introduces 7 diverse programming languages, and for each of them it skips generic hello world nonsense, and dives directly into what makes each of them special.
Each chapter was a lot of fun even though I had some (or pretty massive) amount of experience with some of the languages in the book.
I put my solutions to the exercises on my github in case you're interested, but I recommend not looking at them until you try to solve them yourself.
1. RubyRuby is the most questionable inclusion in the book, since of the kind of people who read programming books for fun, every one of them already knows Ruby. Fortunately the book mostly focuses on metaprogramming, so it won't be too boring for most people who know some basic Ruby.
Another good thing are all the "compare how
2. IoThis is by far my favourite chapter. Io has absolutely insane programming model vaguely resembling message passing.
In "normal" Smalltalk-style message passing the basic operation is:
What Io does is completely reversing this:
send(receiver object, sender's lexical context, message s-expession)If receiver wants to evaluate arguments in the s-expressions (OK, it's not literally s-expression, it's just the best analogy I could come up with, call them ASTs if you wish) - which it does 99% of the time, it sends them back as new messages to sender's lexical context. And there they're evaluated by lexical context object (which doesn't have particularly much to do with sender object).
For "normal" messages it's syntactic-sugared sufficiently that you don't have to think about it.
fib := method(n, if(n <= 2, return 1) return(fib(n-1) + fib(n-2)) )
Here, since method(n, body) has multiple arguments, first argument is evaluated (in sender's lexical context) and assigned to n, then body is evaluated.
But how do you implement high-order methods? Why, by subclassing sender's lexical context of course. I'll let the awesomeness of this sink in for a bit.
Here's Matrix foreach method I wrote for one of the exercises (it's not directly anything they're ask for, so it's technically not a spoiler):
Matrix foreach := method( args := call message arguments xi := args at(0) name yi := args at(1) name vi := args at(2) name msg := args at(3) ctx := Object clone ctx setProto(call sender) for(i,1,xsize, for(j,1,ysize, ctx setSlot(xi, i) ctx setSlot(yi, j) ctx setSlot(vi, get(i,j)) msg doInContext(ctx) ) ) )
First, since method( ) has only one argument (function body), there's no automatic evaluation. Instead we parse argument, extracting names for the first three, and msg for the last.
Then we subclass sender's lexical context into ctx, set some variables in it with setSlot message, then send msg (body which was passed to our foreach as 4th argument) to ctx. Why does it work? That's because evaluating anything is sending a message to some lexical context. Our entire function body is one big message consisting of a sequence of smaller messages like yi := args at(1) name and ctx := Object clone.
3. PrologIf the first thing which comes to your mind when someone mentions Prolog is sudoku solvers, you're right! If you've never done any Prolog, it's a fun few evenings to spend.
Sadly in my experience programming in Prolog is about as practical as "programming in SQL" or "programming in XSLT". It's not really a programming language, it only pretends to be one. If someone took good ideas of Prolog and implemented them as an extension for a real programming language, it might be getting somewhere.
4. ScalaIt feels like modern version of Ocaml in so many ways. Not only it's statically-typed mostly-functional somewhat-object-oriented language, they've thrown everything including a kitchen sink into the language and added such massive amounts of syntactic sugar for each of its features it all looks really weird and gets you thinking that there's surely some simpler syntax which does most of these things just fine.
Scala seems to have significantly less awful standard library than Ocaml - I'm not really a big fan of Java libraries so many people fawn over so much, but just about anything beats the pile of mess Ocaml standard library is.
Scala's syntax, while it won't be winning many converts, is still the best I've ever seen in an Ocaml-like language. Its feature set also looks like mostly a nice improvement over what Ocaml has.
So I'd recommend giving it a serious look if you're an Ocaml programmer.
5. ErlangI blogged about my first impressions of Erlang a few years ago, and giving it another go didn't really change that much.
It's the Ocaml Symptom all over again - it was developed in isolation from the mainstream programming world, so its standard library is awful mess, syntax is awkward as hell, and all the small things other languages get right (like having string type, or ^D to exit) it gets totally wrong. In this case it was isolation at Erlang not in the academia, but it's a very similar problem.
Now by throwing some significant effort and abandoning concern for backwards compatibility you could probably turn languages like Erlang and Ocaml into something actually good, but nobody seems to have any intention of doing so.
This shouldn't stop you from playing with it a bit, but using Erlang in production environment? I don't think so.
6. ClojureLisp is my favourite language I never actually use. Clojure is trying to do something vaguely similar to RLisp - being a sensible Lisp integrated with an object-oriented environment in existing VM (Ruby's vs JVM). And just like RLisp Clojure also attempts to fix one of the worse aspects of Scheme and such traditional Lisp dialects - far too many completely worthless parentheses.
It makes some very different choices too, and that's part of the beauty of Lisp - you can stretch the concept of Lisp really far, and it's still Lisp in the end.
Anyway, If I accidentally win a few billion drachmas somehow, I'll hire a bunch of people to turn RLisp into a real programming language.
7. HaskellHaskell is a wonderful programming language - I'm surprised it's not used more in psychology as it'd make for some really great case studies in Stockholm Syndrome.
Here's a stylized history of Haskell design, in which they've been digging themselves deeper and deeper with each decision:
- Traditional static typing doesn't handle high level functions well, so let's add a really sophisticated type system.
- Our new sophisticated type system requires too much typing, so let's add type inference.
- Type inference cannot handle programs with mutable state, so let's remove all mutable state.
- Without mutable state we cannot actually do much, so let's add monads.
- Nobody understand monads, so let's make hundreds of tutorials "explaining" monads in terms of containers, astronauts, dragon liars, and high grade nuclear waste.
- and so on
What's surprising is how many Haskell programmers don't understand that monads are simply a hack to make I/O in Haskell bearable, they seriously think monads are the greatest thing ever which should be ported to programming languages that don't really need them, and everything else Haskell did as a part of general digging itself deeper and deeper is the One True Way to Program.
Disregarding that rant, while monads (and comonads, and arrows, and the rest of such insanity) have no place in any sane language, they are fun to play with for a bit.
SummaryI really recommend this book. It's not meant as a way to learn any particular programming language (and except for Ruby and arguably Scala/Clojure, none of them are remotely suitable for production use), it's a celebration of diversity of programming languages.
Or at least it will give you better arguments for your rants.