Language and Expression
http://www.kortexplores.com/node/69
Year Written:
1999
Language
is the way the brain attempts to symbolically express and explain its
abstract thoughts to itself and to the outside world. As someone who
regularly attempts to communicate abstract ideas to both humans and
machines through the use of English and various computer languages, I've
always been aware to some degree of the limitations of language. But
recent efforts to express the same abstract concept in two very
different computer languages made the degree to which my thought
processes are influenced by language especially clear. While the
observations to follow resulted from working with computer programming
languages, I believe that they also apply to the effects of more
conventional languages on human thought processes.
Consider that a literary work is typically composed of two very
different aspects - the plot and the prose. The prose constitutes the
entire tangible expression of the work - the words that assembled in a
specific order and taken together accomplish the purpose of the work.
The words that make up the tangible expression of the work are available
to anyone with a dictionary, and can be used for a wide variety of
purposes, but only become this work when assembled in the specific way
that is unique to this particular work.
The real essence and purpose of the work is defined by the plot, and
yet the plot is an entirely abstract entity that doesn't exist within
the tangible expression of the work. In spite of not existing within the
tangible aspects of the work, in many ways the abstract plot is more
important to accomplishing the purpose of the work than the prose that
implements it. It could be said that the plot is the right brain's
abstract idea and the prose is the left brain's attempt to define that
abstraction within the constraints of whatever language tools it has
available. The degree to which the work is successful is the measure of
the ability of the prose to convey the intangible abstract plot from the
writer to the reader.
The same division between abstraction and implementation that exists
within all well written literary works also exists within all well
written computer software. The abstract concepts and logical structures
of a program are implemented within its tangible source code. The better
the programmer is able to conceive of an abstract logical solution to a
given problem, and then implement that solution in a coherent and
effective way using commonly available computer language tools, the
better the finished product.
In the past, while I worked in both PDC Prolog and Pascal, I used
these different languages on very different projects - selecting the one
which best fit the abstract idea I was attempting to express in
computer code. Since each project was written almost entirely in a
single language, for most of my programming career I've been able to
work for long periods in just one language, minimizing the trauma of
shifting back and forth. I was aware of a certain amount of "transition
trauma" when switching between projects written in different languages,
but dismissed much of it as just the effort required to adjust to the
often very different abstract logic structures of those projects. It
seemed that I experienced much of the same mental adjustment when
shifting between writing projects while pretending to be an author.
One of my latest projects has been to write software to allow my
customers to use Windows CE based handheld computers for entering
inspections on-site. Unlike my previous projects where I could choose
the language that best fit the concept I was trying to express, this
time I was forced to use the C++ programming language solely because it
was the only one available at the time for the target hardware platform.
I would never have selected C++ for this project on its merits as a
programming language. To the contrary, I consider C++ exceptionally
inappropriate for such a complex and mission critical application, and
have avoided using it in the past. But since no one other than Microsoft
was willing to offer a software development system for WinCE, I had to
use the tools that were available - and that meant the CE variant of
C++.
As a fully compatible extension of an existing system, from the
outside the new WinCE software written in C++ must by definition be an
attempt to express the same abstract concept as the desktop software
written in Prolog. However, even though I began with the express
intention of implementing an already established abstract concept that
I'd already implemented in another language, the nature of the different
language in which I was now attempting to implement that same abstract
concept greatly influenced the results.
After finishing the first version of the WinCE software, I returned
to working on software written in Prolog. It was over a month before I
had reason to return to the C++ source code for the WinCE project. To my
now Prolog configured brain, on first glance the C++ code that seemed
so clear and obvious just a short time ago appeared to be just so much
unintelligible gibberish. It took a while for my brain to ratchet itself
around sufficiently to where the strange symbols started to suggest
meanings. After sufficient additional review to get my brain back
thinking in C++, it all came back and started to make sense - at least
as much sense as is possible with anything written in C++.
As I had to switch back and forth between Prolog and C++ in rapid
succession over the next couple weeks, I was increasingly struck by just
how different the internals of the programs had become. On the most
basic and obvious level it's probably no surprise how necessary it was
for my brain to be thinking in the appropriate language in order to
extract the intended meaning from the symbols and syntax of source code
written in that language. But the nature of language had a more profound
impact on my thought processes than simply defining the symbols and
syntax rules in which I was working.
In spite of the fact that I wrote them with every intention of
implementing exactly the same abstract concepts, the adjustments and
accommodations required by the different languages in which each program
had been written had required significant differences in the final
results. Not only were there significant differences in the expression
of those abstract concepts, but the original concepts had been altered
as well. I'll try to describe the differences without getting too caught
up in the sort of details that only a fellow programmer would
appreciate.
The software handles data entry tasks as part of a larger real estate
inspection system. Since every property is different, every inspection
the system handles must also be different, requiring a high degree of
flexibility. An inspection is composed of a variety of data types
(multiple choice, numbers, narrative, etc.), with each data type
requiring a different way of interacting with the user. These data types
are intermingled within a given inspection as needed with little regard
for the difficulties faced by the software. To compound the
difficulties, the software allows the user to change the inspection
format "on the fly" - setting up the logical equivalent of the cartoon
character sawing off the tree limb on which he's sitting.
At the heart of the software written in Prolog is a central
dispatcher that controls the logic flow of the program. In the abstract
this dispatcher and the various logic paths available to it are shaped
much like an octopus, with the dispatcher as the body and the various
logic paths radiating out from the center. The dispatcher functions as
an expert system, using a crude form of artificial intelligence to
monitor the state of the system, compare it to the guidelines provided
by the user defined inspection format, and decide on a keystroke by
keystroke basis what to do next. The dispatcher sends the focus of the
program down various logic paths, with the focus returning back to the
dispatcher after resolving each logic path.
While I eventually managed to build a C++ program that adequately
handles the data entry operation, the resulting program is far less
flexible and powerful than the software written in Prolog. In Prolog
each statement can have multiple alternative solutions that succeed or
fail at the moment of execution, dynamically creating a wide variety of
potential logic paths that appear or disappear based on the conditions
the software encounters at run time. In C++ every possible alternative
must be "hard wired" at the time the program is written.
The limitations of the C++ language made it difficult to replicate
the "octopus" type abstract structure. Rather than a logic flow built to
automatically return to the central dispatcher even if a given logic
path fails, each possible logic path in the C++ program must itself
determine what will happen next. Any logic path in C++ that doesn't
accommodate any and all conditions it encounters could not only fail as a
logic path, but also crash the entire program. There's no backtracking
out of a failed logic path and trying a different one in C++ like there
is in Prolog.
As a direct result of the object oriented nature of the language, the
"intelligence" of the C++ program is dispersed and the central
dispatcher ends up looking more like a centipede, with each
semi-independent logic path determining which segment of the dispatcher
next receives the focus. Due to the "OOP" (object oriented programming)
aspects of C++, each segment of the dispatcher must operate as a
semi-independent entity. The requirement to break the internal structure
of the program into semi-independent objects makes it difficult to deal
with situations involving the sort of dissimilar but interrelated
objects that are so common in real life, restricting the complexity of
processes that can be expressed in C++.
The crude artificial intelligence of the software written in Prolog
provides the dispatcher a far greater level of internal flexibility,
allowing it a wider range of ways to respond to the conditions it finds
at the moment of execution. When faced with an unexpected situation, the
software is far less likely to find itself caught up in the sorts of
logical paradoxes and dead end logic paths that will cause the software
to crash. This innate flexibility and ability to deal with unexpected
situations, made possible by the nature of the language used to express
it, becomes even more important in the more sophisticated parts of the
inspection system.
The internal differences in the resulting programs graphically
demonstrate that the effort to express abstract ideas within the
constraints of language is a far more complex process than simply
exporting ideas filtered through language. When faced with the need to
express abstract ideas outside of the physical confines our the brains,
those areas that handle abstract reasoning are quite capable of making
significant adjustments to their original "pure" abstract concepts in
order to accommodate the limitations of the brain's language processing
areas. In essence, the limitations of our ability to express abstract
ideas determine to some extent the nature of the abstract ideas we are
capable of thinking.
I'm amazed that given the same abstract concepts and the same
physical "wetware" to work with, my single brain can come up with such
divergent results when operating from the different perspectives imposed
by different languages. Small wonder humanity has achieved such diverse
explanations for the world and our place in it considering the
differences in the languages we've invented in our ongoing efforts to
explain ourselves to ourselves.
thanks...avery nice blog
BalasHapus