The Skeptical Methodologist

Software, Rants and Management

Does a certain language force you to think in a certain way?

For inspiration, see what psycholinguists say in regards to natural language.

In natural language, it is no longer believed your mother tongue constrains your thoughts in any way.  On the contrary, it may simply force you to fill in details other languages would leave implied.  Some languages would force you to use geocentric coordinates, for instance, so that you described everything in terms of north, south, east and west rather than ‘in front of you’ or ‘to the right of you’.  Other languages require you to fill in details regarding how you learned a certain fact, meaning that the tense differs whether you were inferring a thing or knew it to be true.  Still another, more popular language (some might know as English) require you to put every event in time using future, past or present tense, while not all languages (like Chinese) are bound by this rule.

I think there is a high correspondence between what we know of natural language and computer languages.   Hence, we can ask a similar question here – does the choice of language constrain you to think in a certain way?  Or more weakly, does a choice of language require details other languages do not?  Our answer will be strikingly similar to the one found for natural languages.

First, no language forces you to think in any certain way.  This may be eye-opening for those who have learned a procedural language and then went on to learn a functional one.  They might claim that the procedural language forced them to think in terms of steps, while functional languages opened their minds to decomposing problems in other ways.  This is absolutely true.  One must realize, though, that you can write functional code in a procedural language.  It’s a way of thinking, and you can absolutely express things generally ‘native’ to one language in another as you see fit.  A more crude saying that exemplifies this point is that “You can write Fortran in any language.”

What we see is not that any language constrains you to think in a certain way, but because of what languages require of you, if you are not exposed to other languages, it is easiest to think in your mother language’s preferred way.

Let’s analyze C++ for example.  Similar to the way French requires every object be a he or a she, C++ requires us to specify how we pass all of our arguments in our functions, whether by reference, pointer or value.  These things are implied by other languages, yet C++ forces you to think about it.  In C++, this turns into a lot of extra specification, but gives us the benefit of faster code if used wisely, while in languages like Python, we have to jump through extra hoops to ensure we pass arguments around efficiently.

Similarly, C++ requires us to tell the compiler whether we want to allocate a variable on the stack or on the heap, a detail that is not required of things like garbage collected languages.  This means that a programmer very familiar with C++ will always think of things like object life cycles and the performance and safety benefits of stack versus heap allocations, while a programmer more familiar with C# will not take these details as seriously (even though C# uses stack and heap allocation too).

On the flip side, in English, we can suppose a gender for every object we like, and we have the ability to speak in terms of geocentric rather than egocentric coordinates.  Likewise, all Turing complete languages can accomplish any goal, it’s just a matter of how verbosely they do so and how ‘natural’ it appears.  Because details like how an argument is passed and where it is allocated are not as important in a language like Python, it is less natural to optimize a Python program based on those things (although entirely possible).  Conversely, because of the requirements of an intuitive understanding of the cardinal directions is required to speak in terms of geocentric coordinates provides a speaker of a geocentric language an uncanny ability to know where they are on the planet, the requirements of thinking about allocation schemes in C++ tends to leave the C++ programmer much more finely tuned to the issues of memory safety and resource allocation.

A keen example of this would be in the RAII idiom found in C++ versus other resource release schemes.  Memory, after all, is only one resource that must be managed, so when it comes to safely releasing files, locks and other resources in the face of exceptions in other languages, some tooling is required.  Compare the try/catch/finally block to the RAII scheme.  Many C++ programmers, including this one, would say that an RAII scheme (or handle/body scheme) is cleaner, reads simpler, and is safer than a try/catch/finally system.  Why does this cleaner result occur?  Because C++ programmers are used to always thinking about resource allocation/free’ing, while other languages this concern is more foreign.

Just so you know this isn’t a C++ fest, consider functional programming.  Many functional programmers have pointed out that a few of our cherished Object Oriented ‘patterns’ are just functional programming in disguise, with “Strategy” being a good example.  In a pure OO language, or an OO style of C++, strategy patterns require a bit of up front documentation and boilerplate, while in languages where functional idioms are expected, no such pomp and circumstance is required.  Is the strategy pattern or lambda functions a better way to fulfill this need?  Considering that like try/catch/finally blocks and RAII, both can express the other and are completely equivalent, there’s no mathematical or computational reason to prefer one over the other.  However, I think most people who are familiar with both approaches would agree that simple lambda functions are a cleaner way to solve problems the Strategy pattern could solve.

The take away here is that, yes, certain languages prefer you think in certain ways.  But problems are best solved in a myriad of ways.  The best way to learn about these different problem solving techniques is actually not to solve them in your mother tongue, but rather solve them in a cleaner tongue and figure out how that solution translates.  We should not be teaching OO programmers the Strategy pattern, for instance, but rather teaching them higher level functional programming – then showing how the strategy pattern can fill this role in a purely OO language or design.  Similarly, while thinking of the gender of an object can lead to some insight into design and understanding of it, it’s boilerplate for the most part.  Better to leave the gender ambiguous or non-existent, but be keenly aware of gender-requiring languages so that the concept is not entirely foreign to you.

Another deeper understanding to take away from this may be that the languages that are the ‘best’ are those that allow us to specify the most, but require us to specify the least.  Imagine a form of English that can be written tense-less, yet one can add flow of time information as needed as an example.

August 29, 2010 Posted by | Uncategorized | Leave a comment

Metaphors

A technique I like to use for creative insight is to map two concepts together using a metaphor, and then fill in the blanks where they don’t line up.

For instance, writing prose and writing a program have a few similarities and a few differences. When writing prose, we plan and arrange linearly since that is the main way our words will be read. In programming, however, we plan and arrange fractally since programs can make much more of reuse and referring to generic/abstract code.

Editing and proofing have the same similarities save one. For instance, both programming and prose can make use of static tools to some effect. Spell checkers and to an extent grammar checkers have made our lives easier and a red squiggly line under a misspelled word is as helpful as an immediate compiler warning from the line you just finished. Both these tools have their drawbacks too – they’re too focused, and can only catch ‘easy’ errors. A spell checker can’t tell you if your article is convincing, nor can a lint tool check your business logic.

The best means of improving quality of prose, and to an extent programming, is still the peer review and edit cycle. Due to the nature of our product, we have more tools in the chest besides peer review, however the nature of the review is almost exactly the same even though each product has drastically different uses and signs of quality.

Enough of similarities – how about differences? I can’t find, for example, an analogue to testing in writing. Testing seems to be completely derived from software (indeed, while it has some similarities to engineering tests, software style testing and debugging probably has the scientific method in its lineage rather than its suspected engineering heritage). This difference is interesting, but adds little to the discussion on the software side.

A more important difference is the editor role, and the general role of editing. It’s reasonably well established in literary disciplines that your first draft is, well, a first draft. You will be re-arranging it, slicing it up, adding here, taking away there, and fine tuning your diction before you’re done. I believe in software this is very similar to the practice of refactoring, but to a much larger degree. In software, refactoring is something we do if we have time, or something we’d like to do more of. In writing, editing is seen as just as value added as the original writing. Being an editor is a dedicated profession, while being a ‘refactor-er’ would be seen as skirting the important work of cranking out KLOC.

Maybe there is a lesson in here? Maybe software’s curse of reinventing the wheel even can be extended to re-discovering what other writers have known for centuries? Should we be spending as much as, if not more time rewriting and refactoring our programs as we do on our initial designs and prototypes?

August 9, 2010 Posted by | Uncategorized | Leave a comment