Idioms, motivation, design

November 27, 2012 at 9:00 am
filed under Coding
Tagged , , , ,

This post, called Why learning Haskell/Python makes you a worse programmer, is from ’06, but the lessons are still valid: don’t try to shoehorn one language’s idioms into another, no matter how powerful or useful those idioms might be. People will find your code harder to read, not to mention the amount of friction you’ll encounter, as the author did, with the language itself and common APIs.

But there’s more.

On idioms

I wonder if this is something which is underappreciated: just because you can implement a construct in a given language doesn’t mean you should.

You can invent a Maybe type in Java. But unless all the APIs you use also use it, you’ll either need to wrap every API call you make with a Maybe layer, or abandon it altogether. Similarly, the author tried to cram higher order functions into C# and came away frustrated. The language doesn’t encourage it, the APIs don’t use it, and nobody who reads C# will grok it.

Haskell could’ve had this problem, incidentally. If instead of using Maybe consistently, APIs all could have used different types. But they didn’t, so Maybe feels like a first-class construct. So whether something is first class or idiomatic isn’t just a property of language primitives, but the core libraries and such.

Also, some languages are more amenable to being extended in this way. Lisp’s macros make it easy to modify and extend the language transparently, using the same or similar constructs the language designers used. I’m not so sure about Haskell, except to say that with infixr, et al, you can create your own operations/primitives which do more or less what you want. Open polymorphism via typeclasses also helps.

On motivation

To some extent, it is demotivating to learn powerful constructs like these which have no practical equivalent in another language. He talks about writing out programs in Haskell after the fact, just to prove a point, and how that demotivates him. I’ve done this in anger myself, so I sympathize. But there is something constructive here: instead of doing it after, do it before.

Me, sometimes if I don’t really understand what I’m writing, I reach for another language as a way to work the problem out. Peter Norvig says that Python in particular lends itself to pseudocode which is in fact real code, and I think there’s a lot to be said for that. Occasionally I might use Clojure for this, as well; Lisp is the Maxwell’s Equations for software, right?

What I’m really doing is just going to a “native” language, or some language which I know can attack the problem elegantly. Then, when I feel I really understand the problem, I can tackle it in the language at hand.

(That said, sometimes figuring out how to express something in the actual language is the problem at hand, of course. I’ve encountered this frequently as I’ve picked up C++. As Scott Meyers says in Effective C++, C++ is actually a federation of languages, and it shows.)

Haskell might be harder for this, although I’m not sure. Concepts like monads might not be easily implemented in Java, but the idea of chaining/composing operations, or exploiting the type system to do some of your work for you aren’t foreign.

On design

Even if you don’t get to use all your fancy idioms and constructs in a mainstream language like Java, concepts like immutability, composition, supremacy of data, and minimizing side effects can still inform idiomatic OOP/imperative design.

Creating objects with only static methods isn’t idiomatic, but a “normal” object which happens to have minimal, explicit state should be just fine. Less state means a smaller API surface, which is better for everyone.

Composition is actually huge. You can’t always exploit it to its fullest — composition works best when there’s language-level support for it — but there’s a ton of merit to the the idea that your program should be built out of small pieces which work well together.

These pieces should be as atomic and orthogonal as possible, with little knowledge about one another. As much as possible, data should be the common interface between these components.

And so on.

On essence

Odds are that you’re probably going to learn some things you can’t use in the most immediate, concrete sense. If you end up liking functional programming, you risk unhappiness when you can’t bring that stuff with you to work or school or what have you. But.

Just as when you learn your second programming language, you begin to learn the concepts that underpin all programming languages, I feel that learning something like Lisp or Haskell will give you yet more, equally valuable insights. These languages approach the topic from such a different perspective that they are categorically different, and you will often see old problems or constructs in a completely new light.

%d bloggers like this: