Programming “in” a language vs programming “into” a language

I’m currently reading Steve McConnell’s Code Complete (for the first time – yes, I know that’s somewhat worrying) and there was one section was disturbed me a little. For those of you with a copy to hand, it’s in section 4.3, discussing the difference between programming in a language and programming into a language:

Programmers who program “in” a language limit their thoughts to constructs that the language directly supports. If the language tools are primitive, the programmer’s thoughts will also be primitive.

Programmers who program “into” a language first decide what thoughts they want to express, and then they determine how to express those thoughts using the tools provided by their specific language.

Now don’t get me wrong – I can see where he’s coming from, and the example he then provides (Visual Basic – keeping the forms simple and separating them from business logic) is fine, but he only seems to give one side of the coin. Here’s a different – and equally one-sided – way of expressing the same terms:

Programmers who program “in” a language understand that language’s conventions and idioms. They write code which integrates well with other libraries, and which can be easily understood and maintained by other developers who are familiar with the language. They benefit from tools which have been specifically designed to aid coding in the supported idioms.

Programmers who program “into” a language will use the same ideas regardless of their target language. If their style does not mesh well with the language, they will find themselves fighting against it every step of the way. It will be harder to find libraries supporting their way of working, and tools may well prove annoying. Other developers who come onto the project later and who have experience in the language but not the codebase will find it hard to navigate and may well accidentally break the code when changing it.

There is a happy medium to be achieved, clearly. You certainly shouldn’t restrict your thinking to techniques which are entirely idiomatic, but if you find yourself wanting to code in a radically different style to that encouraged by the language, consider changing language if possible!

If I were attacking the same problem in C# 1 and C# 3, I could easily end up with radically different solutions. Some data extraction using LINQ in a fairly functional way in C# 3 would probably be better solved in C# 1 by losing some of the functional goodness than by trying to back-port LINQ and then use it without the benefit of lambda expressions or even anonymous methods.

Accents and Conventions

That’s just between different versions of the same language. Between different actual languages, it can get much worse. If you’ve ever seen Java code written in a C++ style or vice versa, you’ll know what I mean. I’ve previously referred to this in terms of speaking a language with an accent – you can speak C# with a Java accent just as you can speak French with an English accent. Neither is pleasant.

At the lowest level, this is likely to be about conventions – and I’m pretty sure that when Steve writes “Invent your own coding conventions, standards, class libraries, and other augmentations” he doesn’t actually mean us to do it in a gratuitous fashion. It can be worth deviating from the “platform favoured” conventions sometimes, particularly if those differences are invisible to clients, but it should always be done with careful consideration. In a Java project I worked on a few years ago, we took the .NET naming conventions for interfaces (an I prefix) and constants (CamelCasing instead of SHOUTY_CAPS). Both of these made the codebase feel slightly odd, particularly where Java constants were used near our constants – but I personally found the benefits to be worth the costs. Importantly, the whole team discussed it before making any decisions.

Design Patterns

At a slightly higher level, many design patterns are just supported much, much better by some languages than others. The iterator pattern is a classic example. Compare the support for it from Java 6 and C# 2. On the “client” side, both languages have specific syntax: the enhanced for loop in Java and the foreach loop in C#. However, there is one important difference: if the iterator returned by GetEnumerator implements IDisposable (which the generic form demands, in fact) C# will call Dispose at the end of the loop, no matter how that occurs (reaching the end of the sequence, breaking early, an exception being thrown, etc). Java has no equivalent of this. Imagine that you want to write a class to iterate over the lines in a file. In Java, there’s just no safe way of representing it: you can make your iterator implement Closeable but then callers can’t (safely) use the enhanced for loop. You can make your code close the file handle when it reaches the end, but there’s no guarantee that will happen.

Then consider the “server” side of the iterator – the code actually providing the data. Java is like C# 1 – there’s no specific support for implementing an iterator. In C# 2 and above, iterator blocks (i.e. methods with yield statements) make life much, much easier. Writing iterators by hand can be a real pain. Reading a file line by line isn’t too bad, leaving aside the resource lifetime issue – but the complexity can balloon very quickly. Off by one errors are really easy to introduce.

So, if I were tackling a project which required reading text files line by line in various places, what would I do? In Java, I would take the reasonably small hit of a while loop in each place I needed it. In C# I’d write a LineReader class (if I didn’t already have one!) and use a more readable foreach loop. The contortions involved in introducing that idea into Java just wouldn’t be worth the effort.

At a much higher level, we get into whole programming styles and paradigms. If your natural inclination is to write imperative code, you’re likely to create a mess (or get very frustrated) in a functional language. If the problem really does call for a functional language, find someone else to help you think in a more functional way. If the problem suits imperative programming just as well as it does functional programming, see if you can change the environment to something more familiar.

Conclusion

I’m not suggesting that Steve’s point isn’t valid – but he’s done his readers a disservice by only presenting one side of the matter. Fortunately, the rest of the book (so far) is excellent and humbling – to such a degree that this minor quibble stuck out like a sore thumb. In a book which had more problems, I would probably barely have even noticed this one.

There’s another possibility, of course – I could be competely wrong; maybe I’ve been approaching problems from a restrictive viewpoint all this time. How about you?

12 thoughts on “Programming “in” a language vs programming “into” a language”

  1. I believe that you are correct that both viewpoints are important. What I believe is trying to be said about programming in a language is that some people approach problems by thinking only in terms of what they know is possible in the language they know. If you’re not restricting yourself to one language you might realize that a certain problem is better solved using another language. Perhaps one which can handle certain operations better than the current language.

    I think this is one of the big reasons why there are languages which have libraries written in other languages; simply because the other language can handle certain problems more efficiently.

    Like

  2. Jon,

    I think Steve wants to say that don’t be limited by language to express your thoughts. Try to see how you can express yourself the way you think about it using the language.

    Usually, we (atleast me & when beginning) try to look at what features language provides & try to express code using those constructs.

    Your point is valid too. However, .net is a different game. They changed the language to support linq & other dynamic stuff.

    Like

  3. Most language have several standout features or patterns which allow for the richest expressive power (C++ and generic programming for example). My approach assumes that many algorthims and structures stand a good chance of being best represented by these patterns and features of the language. So when taking on a new language I usually try to get familiar with these features and patterns. Usually a couple of sample programs or porting over some old library code.

    From there I try to take an even handed approach balancing between what I’m comfortable with and applying the language specific patterns appropriately.

    Like

  4. I think Steve & Jon’s thoughts could be expressed better in this terms:

    To be a good language citizen you need to constrain your mind in some ways. Don’t do it. Forget your current language and go straigh to C# 3 :)

    Like

  5. I think you’re taking a much too narrow view of Steve’s point. He wasn’t saying that you should treat all languages the same. He was saying that you shouldn’t constrain your thinking by the conventions of a particular language. The best way to approach a problem is to think about it in the abstract first, then figure out the best way to make it concrete. This sounds obvious, but many developers never bother with the abstract. They jump straight to the concrete expression in a particular language, and they are unable to think beyond that expression; therefore they are limited in their understand of the concept and their ability to express it. By considering what you want to express in a language-neutral fashion first, it is easier to consider all of the options before diving in. You are referring to implementation details like the iterator pattern; I think Steve was talking about concepts at a much higher level.

    Like

  6. I’m on my second copy of Code Complete, I wore out the first. Yeah, I’ve struggled with that little bit of wisdom myself… never have came up with a clear idea of “exactly” what he meant. I have just always assumed that its me that is deficient.

    Like

  7. Which version were you reading the Code Complete 2 or the original? I read the original many years ago and yes tsk..tsk that you’ve left it till now to read it. :)

    This book remains top of my list of books developers must read.

    I think the overall point that Steve is driving at is communication with future versions of oneself or other developers.

    I have to say though having had much experience constructing code in a manner that conforms to the concepts laid out in the book it has had mixed success in part due to reason you laid out.

    Many developers when reading my code find it hard going because strangely they find the level of abstraction difficult.

    You’d think the ability to abstract is a key skill that all developers would have but that isn’t so in my experience. Most find it difficult to trust that a function that says it does x will actual do x and nothing but x. So they have to follow a call to x and trace through its code to make sure for themselves. Of course when x also calls y and z then the whole point of good abstraction is completely unraveled.

    I’ve had to ask myself why this is and as yet I’m not sure I fully understand it. I think it has to do with a culture which developers that program “in” a language build up.

    For example a well factored OO design is not something the typical Javascript developer has to deal with. Few have ever use a Function to define a class and many are quite happy to write one long procedure to respond to UI event rather factor it into a set of functions.

    Like

  8. I’m reading v2.

    I certainly agree that considering abstraction is important, but I *also* think that when choosing between different potential designs it’s worth bearing in mind which language you’re going to implement those designs in.

    The way I read the text (and we’re all interpreting, of course) is that Steve discourages that – that he finds it limiting. I just find it practical, and I’ve read too much code written by people who want to do things their pet favourite way whether it’s applicable to the implementation language/platform or not.

    Jon

    Like

  9. I too recently read through Code Complete for the first time. This bit of advice stood out to me too.

    I think for the most part he is saying: Don’t let the language you are using limit you. And I think he means more standard libraries than the actual language itself.

    Maybe it’s just because I’ve seen a lot of C# that wanted to be Python or a lot of JavaScript that wanted to be C# lately, but I can definitely see the danger in going too far with the concept.

    Like

  10. Yes, maybe it would be nice to develop some part of project in a diffrent lang than c#. But in most companies I worked for there was team coding in one language or max two languages… If now you want to introduce 3rd language there is a problem because your solution might be great in php instead of asp.net but what if you decide to leave a company who is going to support it? If the project is huge and based in c# 2.0 do you know how hard it is to upgread to c# 3.0 ?
    Author missed realistic approach it’s not academic coding to impress lecturer it’s a real life… which is far from being perfect. And from my perspective I think learning c# and best practices in .net makes learnign curve steep enough…

    Like

Leave a comment