I learned the correct name today for a theory I have known for a very long time: The concept that your language shapes and influences your thoughts is formally called the Sapir-Whorf hypothesis. I have also heard it attributed to Ludwig Wittgenstein and Ferdinand de Saussure; more information is on wikipedia.
The Sapir-Whorf hypothesis had an influence on science as well as literature. George Orwell’s classic “1984″ contains a language called Newspeak that is designed to eradicate illoyal thought by abolishing words like “free". The reasoning is that once you cannot fight for freedom, because the very word does not exist in your language, rebellion becomes pointless. Another example is Samuel R. Delany’s “Babel-17″, where a fictional language denies its speakers independent thoughts and transforms them into traitors and terrorists; it is used as a weapon of war. The notion that certain works lose their meaning when translated to another language (for example, the Quran) is also an example of this principle.
The validity of the Sapir-Whorf hypothesis is under dispute; if it were all true, then translation between different languages would be impossible. Chomsky’s quest for a universal grammar that is innate to every human also goes counter to the Sapir-Whorf hypothesis. But neurolinguistic research points to the fact that certain areas of the brain are indeed influenced by a speaker’s native language.
Leaving the realm of human languages, how does this hypothesis apply to computer programming languages? From a purely functional point of view, all programming languages are equal – they are all turing complete, which means that any of them can be used to solve any problem as well as the others. So as regards the computer, it does not care about which programming language is used.
The reason why there are still hundreds of different languages and language dialects is not the computer, but the human who has to read and write the code. So the fundamental problem in language design is not designing a language that will allow you to do as much as possible, but one that will allow you to think about your problems in the most meaningful way.
The people who invent those languages appear to have been aware of their effect on the human mind for quite some time. Everyone knows Edsger Dijkstra’s quote, “The use of COBOL cripples the mind; its teaching should therefore be regarded as a criminal offense.” And of course the famous “A FORTRAN programmer can write FORTRAN in any language.” The implication is that your first programming language indeed shapes your mind and determines how you write code in subsequently learned languages.
In my experience, the language you use does indeed affect how you think about problems. I started out with imperative programming languages (C, Pascal), went on to object-oriented languages (Modula-3, Delphi, C++), learned functional programming in my first year at university (with Standard ML), and acquired a host of languages on the way (among them Perl, Python, PHP, PostScript, SQL, and a number of “lesser” languages like Bourne Shell or awk). The only thing I never properly learned is a logical programming language like Prolog (though I did hear a lecture about automated theorem proving, which essentially detailed the inference process of Prolog.)
Object-oriented programmers (especially those reared on UML etc.) tend to see everything as objects that pass messages to each other; objects with a state, a lifetime, and methods that can be called. While this is suited to most modeling tasks, good object-oriented design for other domains is very difficult, as no readily apparent mapping between parts of the problem and a hierarchy of objects exists. That is one reason, I think, why all the exercises in classes on object-oriented software design are always about modeling some part of the real world, and not about modeling an abstract concept. Tasks like stream processing or symbol manipulation are hard to capture properly in object-oriented models.
Purely functional programming is another extreme; it is extremely well suited for symbol manipulation and stream processing. When I learned it, functional programming inspired a view in my mind of lists and other data structures, flowing through functions and getting mangled and massaged on the way. I solved some exercises for the above mentioned lecture on theorem proving in ML, and the code was exceptionally clear and concise; some theorem provers were less than 20 lines of code. But once imperative elements enter the language, and the need to keep state arises, the functional model becomes rather unwieldy. There are object-oriented functional languages (OCaml being the most prominent example), but I have no experience with them.
Further evidence that the code you write influences how you think about and formulate algorithms offline is this: I encountered a number of algorithms that were exceptionally difficult to program in a modern, imperative or object-orientated language. They were formulated without loops or subroutines, and used jump instructions excessively. The only explanation I can think of is that maybe the authors were used to programming languages that promote this style, like fortran or assembly language. Writing a clean C++ or ML version of such an algorithm requires extensive reformulation, whereas other algorithms (for example, the ones mentioned above) could be implemented in ML in a minimum of time, straight from the description.
But the fact that different programming models promote a different approach to problems can also be used to your advantage. If you know a number of languages, then you can – bar external requirements – choose the language for solving your problem that makes it easiest to think about it. If you are doing symbol manipulation, choose a functional programming language (or a language with substantial functional features, like Python). If the task is modeling, choose an object-oriented language. If you want to query complex data structures, use a logical language like Prolog. Especially in research, many problems can be solves more efficiently by combining a hodge-podge of different languages and use each one in the area where it is best.
For commercial software development, other factors like maintainability tend to be more important, but even there, using an embedded language for configuration or extension can be an advantage.
There are also hybrid languages, like OCaml, which is a functional object-oriented language, or Curry, which is a logical-functional hybrid. Their effect on the programmer’s psyche and problem-solving technique is unclear to me.
And other programming languages claim to be agnostic of the programming model, for example C++. While C++ is mostly associated with object-oriented programming, Stroustrup maintains that other styles like functional programming are also possible in C++. Because of the poor support of features like garbage collection in C++, it does not provide the comvenience of other functional programming environments, though.