

A Philosophy of Programming Languages - mjburgess
http://blog.mjburgess.co.uk/2013/05/a-philosophy-of-programing-languages.html

======
davesims
I've been thinking about this quite a bit myself lately (mostly due to the
excellent ongoing discussion Steve Klabnik started here
[https://groups.google.com/forum/?fromgroups#!forum/philosoph...](https://groups.google.com/forum/?fromgroups#!forum/philosophy-
in-a-time-of-software)).

It seems to me a philosophy of code that begins at the "low" level of binary
and machine instructions, would ultimately reduce to a contemporary
British/American Analytic style of philosophy to the exclusion of all else,
seeing as how the core level of communication is binary -- logic, to the
exclusion of rhetoric, in the classical sense of both of those disciplines.

If you take a logic class at a basic level in both a Philosophy and CS context
(as I did), you'll be struck by the massive overlap -- DeMorgan's theorem,
_modus ponens_ , et. al.

Setting aside for the moment the possibility of alternate CS architectures
(neural nets, quantum computing and so forth), this would _seem_ at first
blush to limit the relationship of all computer languages to a 1:1
relationship with logic.

However this "reductionist" (foundationalist?) approach to finding a true
semiotics of CS may not tell the whole story. As we move from the "low" level
to the "high", say from the domain of machine code all the way up to, for
instance, a rich, expressive Ruby DSL, the question arises, as it does for all
language: have we acquired a surplus of content that cannot be simply
_reduced_ to core rules? At this point things get less Wittgensteinian and a
little more late-Heideggerian, i.e., less analytic and more
eidetic/phenomenological.

To remove the fuzziness from this notion, think of how, for instance, a first-
person shooter creates the illusion of a smooth, analog reality from a rigid,
frame-by-frame progression (as cinema does as well -- and this question has
been explored at length in that world). As humans _interacting_ with the
result of the code, we _infer_ content between the frames -- we make up the
difference and experience the virtual world presented to our senses as
continuous analogical rather than chopped-up and merely logical. Code never
exists in a vacuum -- it is _experienced_ by humans and humans bring meaning
to it, as much as it brings meaning to them.

There's a similar phenomena in OOP, where the meaning of the code is not
merely the sum of its final binary product ("true" or "false") in the world of
machine instructions, but in the metaphor it presents as a model of an object
or event in the world. This code is constantly changing (literally) as it
intends _towards_ richer analogies with the world, and we as coders (and
users) make up the difference by bringing real-world experience to it when we
"read" the code. In other words, code is never "true" or "false" as a function
of its binary reduction, but is a constantly-changing artifact of some human
being's attempt to analogize the world, read by other human beings attempting
to understand and refine that analogy.

In this sense the general problem is, as another poster phrased it so well,
semiotic rather than epistemic or even logical. But I'm not sure a "closing
over" or reducing towards core CS mathematics helps us understand the
ontological status of code, any more than Wittgenstein or the Vienna School
has given us a salutary reform of philosophical discourse with _pure_
analytical techniques in search of a perfect, ambiguity-free symbolic
language.

Language of any kind acquires a surplus of meaning as human beings interact
with it and bring their own analogies to the experience, and I think this
applies to code as well. So it may be that it's OK to move towards a
philosophy of code that takes a phenomenological approach to the _final
product_ \-- the code itself -- rather than (or probably _in addition to_ )
looking for meaning in the binary rules that compose machine instructions.

OP writes:

>> With this in place we can make certain classifications (in a quais-
aristotelian manner): functional languages, object-oriented languages, etc.
And perhaps be radically more precise and classificatory than this with key
properties serving to increase resolution (run-time-modification of objects,
“RMO”: javascript, OO-RMO-HOF-…).

The problem I see with this is that most of these languages are hybrids -- I
can do OOP in Clojure and functional in Ruby and prototypal-fuctional-oop in
JavaScript, etc. So, to me, again, as in language itself, I _prefer_ an
ontology rooted in immediate experience of particular code. Categorization of
an Aristotelian type can be very helpful, but like all reductions, it can hide
as much as it reveals.

What I would advocate in a philosophy of code is multiple starting places
moving towards each other: acknowledging and exploring the rigorous logic
implied by the core rules of logic gates (flip-flops made of silicon and so
forth), the richer semantics of language structures (the Aristotelian
categories of Functional, OOP, Structured, Prototypal), and a Phenomenological
approach to particular code (what does this class/method/function suggest as
an analogy to the real world?).

~~~
kruhft
> As we move from the "low" level to the "high", say from the domain of
> machine code all the way up to, for instance, a rich, expressive Ruby DSL,
> the question arises, as it does for all language: have we acquired a surplus
> of content that cannot be simply reduced to core rules?

No, not if it's still executing on a physical computer.

~~~
davesims
But the computer and its physical state has no meaning unless the output is
_perceived_ (paging Berkeley). That meaning _to the user or coder_ is more
than a function of the position of electrons in silicon, but also, and I would
argue primarily, in the meaning conveyed to the subject/user/coder. Certainly
there is no meaning without physicality, but physicality without subjectivity
is literally meaningless, and that subjectivity brings with it analogies and
more content than can possibly be found in a pure reduction to electrons.

I think if we look hard at the structure of CPU instruction sets, GPUs, math
coprocessors and the like, we'll see even at the lowest level attempts to
present analogies and manage the limits of pure logic _as presented to a human
consciousness_. So even at the lowest level of CPUs, the language of analogy
is present, and that implies that a human subject is going to supply the
content "between the electrons" as it were.

~~~
kruhft
You are taking the system of computer and user as a single system, and are no
longer talking about just the computer. This will lead to more than electronic
reduction in silicon because there is more than electrons and silicon.

There are no attempts to manage the limits of pure logic at the silicon level.
The entire analogy of the CPU is to implement pure boolean logic through
strict controls and limits of voltage levels in analog circuits.

The logic available to humans is the same available to CPU. Godel used pure
logic to create an unprovable statement that was both true and false. What he
did to _create_ such a statement is what computers do not (yet) have, but it
most certainly is not logic, and I think that would be what you say is
'between the electrons'.

But whether we can program and execute this 'insight' on a finite logic system
is another question that is yet to be answered. What we can program we can
execute and thus can be reduced to basic forms of symbolic logic, whether
powered by electrons, pen and paper or the brain.

~~~
davesims
>> The entire analogy of the CPU is to implement pure boolean logic through
strict controls and limits of voltage levels in analog circuits.

But this isn't the whole story either, right? What is "pure boolean logic"
anyway? It doesn't exist even at the lowest levels. Logic is always applied to
a statement of some kind, it doesn't exist as a pure abstraction. It's
interesting you bring up Godel. Russell and Whitehead attempted to map logic
to math in the Principia, and were refuted by Godel's incompleteness. I don't
want to make too much of incompleteness (as many do), but let's not make too
little of it either. At some point logic can only do so much for you, and you
have to resort to analogy. I think this happens much earlier in CPU
architecture than you're allowing for.

What you have at a low level on the CPU are a set of instructions arbitrarily
(to some degree) defined to efficiently model analogical actions like "push"
and "move" and "shift" and the fundamental operations that map to assembly.
And here we've already moved out of the realm of pure logic -> math envisioned
by Russell and we've created logic -> language, by way of analogy. This is, I
would argue, a rhetorical move rather than a logical one. We've already
prepared/redacted the ones and zeroes for human consumption, and assumed a
specific semantic to provide for a human imagination that will accept and
adapt to the semantic.

~~~
kruhft
The instructions in the CPU are no different from the statements in the
Principia, just finite and physically realized. The instructions are
combinations of logic operations, although the logic is now sequential and
having state, which I would think sets it apart from the Principia since I
haven't yet gotten my copy to study. The sequentiality gives rise to monadic
world state, but all is still reducable to logic in the end.

There's no magic in the computer and no analogy other than designing analog
circuits that clamp voltage levels and a very large finite state machine. It's
logic all the way down, limits and all, though instead of incompleteness
there's incomputability. 2 sides of the same coin.

Pure boolean logic can be reduced to symbol manipulation using rules of
substituion and inferrence, but, of course, what is that composed of? Godel
showed that metalogic is made of logic, you just elevate the types.

What is logic made of?

BTW I know computer architecture very well. There's no analogies, just
abstraction.

~~~
davesims
Just as a preface -- this is a great conversation, very provocative to me. If
I make a misstep with regards to to CPU arch, feel free to correct
(naturally).

"The instructions in the CPU are no different from the statements in the
Principia"

As the goal of the PM was to show that math was a function of logic, we can
use 'statements in the Principia' and 'the classical rules of logic'
interchangeably in this context.

There's two questions at play in this conversation. One is whether _in
principle_ the question of the _meaning_ , as such, of software, can be
considered apart from the whole act of perceiving the software, either as code
or as the final UX.

As the idea of "meaning" always involves some kind of communication, a sign or
set of signs shared between two subjects, and as the idea of software pointing
back to its own internal state as the content of this communication would
render the communication pointless and the signs merely tautological, I think
the question of _meaning_ must bring the subject, and the act of perception
and interpretation, into consideration. Scientific statements of fact,
regarding the physical position of all of the machine's atoms and electrons,
have content, but not "meaning" in the common sense of that term intended in
the current context.

The second question, which I'm pretty much winging here (although I have long-
held opinions about the PM and its relationship to the same kinds of
considerations about "meaning"), is whether CPU instruction sets, as subsets
of the rules of logic, dictated by the fundamentals of CS (Babbage, Turing, et
al), are "pure" expressions of logic, or whether in the act of abstracting
logic into the restricted set of instructions, we've performed an analogy.

I think the same question comes to bear -- it matters which perspective you're
taking, whether "meaning" is merely a construction that hides the more
essential question of physicality, or whether ideas like "push" applied to
things like registers and addresses and binary values are linguistic in nature
and convey more than just tautological facts about the physical state of CPU
internals.

I guess this pushes the question out -- why does a computer exist? To
represent to the world the bare facts of its own internal state? Of course
not. A 64-bit address that points to a sequence of binary values is never just
that, it's always a sign that points to something else -- a _person's_
address; a representation of an English character; a shipment of goods; a
lat/long location of some specific place in the world.

So, a "move" or "shift", to you, may reduce backwards to a collection of
logical operations. But even there, what has happened? Nothing's "moved" or
"pushed", that's just an linguistic trick to help us think of the electrical
currents being turned "off" and "on" (and even those are analogies) in
mentally-manageable concepts that map to the rules of logic. To me the
question of "meaning" has already been broached at this point, if we wish to
see computations as significant beyond, again, tautological statements about
CPU internals. If we take the latter point of view, we have mere mathematical
statements that have the same point as pure math -- the elegance (if that) of
its own proof, not any relationship to something external to itself. But of
course, that was never the real point of computers from the very beginning.

The Godel/Russell/Whitehead question is apt here, because this is a very
similar question, if not the same question. Is math a function of logic --
that is to say, can math be "true"? The point of the Principia was to bring
about the dream of the Vienna Circle, a purely mathematical and systematic
technical language to resolve all philosophical ambiguity once and for all.
While there remain a few holdouts for that dream, the general consensus is
that this did not work out -- Godel was only one of many problems with
Positivism specifically, and I would argue, Analytical Philosophy in general,
although in recent years the Analytical/Continental divide has been shortened.

"What is logic made of?"

Yeah. This. That's the question driving all of this.

Good conversation.

------
brudgers
If one wished to pursue this project with systematic diligence, the
ontological questions would necessarily begin with, "What is a programming
language?" and "How do we distinguish programming languages from natural
languages?" -- particularly natural languages such as Wittgenstein describes
as consisting only of "slab" and similar terms.

I fear that such an investigation would not get around to closures for a
really long time if at all, and that OOP and PHP as objects of study would be
so far in the future as to be archaic.

The ontological (and taxonomic) problem can be illustrated with a simple hello
world written in Java running in the JVM running on a 2011 Macbook Air under
OSX. What language is used to write the characters to the screen? A case can
be made for JVM bytecode. A case can be made for C used to write the
hardware's microcode. There's only a better case for one rather than the other
when we have closed over a lot of assumed values.

The general problem of programming language is semiotic, not epistemic. They
consist of symbols and meanings, and while these my glob together here and
there - FORTRAN in any language is still possible.

~~~
mjburgess
Yes, that's the standard compusci response, and that's why debates in this
area are presently fruitless. I dont really care to know to what extent PHP
can be written in first order logic, nor does that help anyone decide between
PHP and Javascript (via Node), for example.

With any philosophical project there are assumptions that you hold fixed and
work that you assume "has been done" (or could be). Either way,

I think there is substantive and helpful contributions to be made by
forgetting where programming languges come from, by ignoring their syntax and
by treating their standard implementations as worlds-to-be-explored.

And if you like, the above statement is my starting point, and implicit
rejection of the compusci approach which is to ask all the questions im
ignoring.

~~~
brudgers
That's a philosophical response, for that is my background. On the other hand,
my general reaction is that the essay lacks rigor. Kant's _Prolegama to Any
Future Metaphysics_ may not set an obtainable standard for this sort of thing,
but it may prove to be a useful guide.

Perhaps we are always required to make assumptions in order to act
philosophically - even if I am inclined toward the belief that though we start
somewhere, starting to do philosophy comes earlier in the day than any
decision to assume. In other words, we don't assume our starting point or
arrive at it after packing our bag - once we start packing our bag, we are
well into the act.

I think the study of computer languages can tell us interesting things of the
sort which philosophers - and particularly natural language philosophers -
have found interesting over the more recent past. But I find a great-chain-of-
being approach dubious in regard to generating epistemic epiphany.

~~~
mjburgess
Oh it certainly lacks rigour. I was just outlining "an intention to be
rigorous" to see what the response would be. There seems to be, so far, quite
a lot of interest in this kind of project.

~~~
brudgers
But alas the taxonomy of programming languages is a solved problem. There is
Lisp. And there is Blub.

Or less t-rolled: McCarthy and Von Neuman.

Or more poetic: Dionysian and Saturnial.

Rigor comes in many flavors. The starting point for all of them is rigorous
thinking. One of the signs that my thinking is not rigorous is that I wind up
proving the point I set out to prove. Then again, setting out to prove a point
ought to be a warning flag.

Even if it is inevitable that I do so. The key to rigor is recognizing that I
am doing it. Lisp and Blub was where I wanted to go. My dissatisfaction led me
to McCarthy and Von Neuman and that to another metaphorical connection between
programming languages and literary criticism. And that fits with my larger
interests; those being the ones which dispose me toward writing about
software.

~~~
mjburgess
As I said towards the end of the piece the intention is to come up with an
abductive process an, "inference to the best representation", a formalized
method for deciding between languages. I am aware that there are various
taxonomies, and perhaps I shouldnt have made the aristotleian comment because
it was rather misleading.

My intention was to take an honest (you may say phenomenological) look at
programming languages: to have a system by which the idioms of the language,
its communal metalogics, etc. are all part of how we assess a language. Not
the reductionism of the "procedural-functional", pre-existing landscape.

I guess my point in referencing this landscape was to point out how inadequate
it is, and how there might be a more complex and useful way of reasoning
_between_ languages.

My next article on the subject, which I'd imagine will follow soon, will
certainly be slightly refocused and clearer. This is very much a just-
finished-typing first draft that I put out to see what the response would be,
and what the appetite for this kind of analysis in the programming community
is.

------
kruhft
> We are currently in a state of paralysis with respect to educating decision-
> makers within applied software development because the arguments made for
> one language or another are small incomparable islands that admit only
> buzzwords.

In my experience, decision makers don't want to be educated about the benfits
of your favorite language. They want to use a 'full stack' supported solution
that has corporate backup and industry acceptance. They want to be able to
hire someone to take over your code when you leave.

In the end, you can compute anything compuatble with any Turning complete
programming language, although some are more elegant than others at certain
problems. Human psychology will lead you to desire what you don't have, which
in this case is your ideal niche language for solving your current problem at
your shitty job. In the end languages are just tools and decision makers are
providing you with the tools you are to use to do the job which minimizes
their risk and maximizes their return.

And if your language is so great and will solve all your problems in an
elegant and productive way, then make something with it and start a successful
company. Then, if you make it for 20 years, wait for the articles saying how
'uneducated' you are having used it and you should be using some university
ressearch language based on n-th level hyper-metalogics because you can write
fib in 21 symbols.

~~~
mjburgess
>In the end, you can compute anything compuatble with any Turning complete
programming language

Well it's this defeatist position i'm arguing against.

> you should be using some university ressearch language

I'm largely a PHP developer / "architect" by trade; I'm not in the business of
pushing Haskell onto CMS developers.

I am interested in the programming language debate, and I'm not convinced "the
market" is the best judge of what the most useful language is. That it
happened to be, for example, the internet was coming of age during PHP's
invention which gave us a generation of script-kiddes (98 - 06) seems to me an
accident of history. This accident is being corrected by Zend Framework and
corresponding language changes (06 - 13), so by today PHP is a language which
resembles a pythonized java, rather than a javascripty perl.

The market in this instance is doing precisely what has been recomended by the
leading _theoretical_ voices in this area: coming from Zend, Sympfony, etc.

My intended contribution is to provide a conceptual framework in which to make
sense of these changes, to advocate for these changes, and to compare
potential changes. Mailing lists are abound with favorite features, I've yet
to see a feature suggestion with a _complete_ argument of the kind I would
advocate.

Though some of the very best do actually get 95% of the way there (ontology:
showing the new feature in other languages to "get a sense of what it is";
epistemology: showing how to reason about it in different areas; abduction:
showing how it represents problems _better_ than current technologies): if you
look at a modern high quality PHP-RFC today you're getting very close to what
i'm proposing.

The open source market of merit is putting these individuals in positions of
power over the evolution of languages, it would be useful - i suggest - if we
could have a standard which provides the means for establishing good arguments
from bad arguments in this area.

~~~
kruhft
The market will never be the best judge of what the most useful language is,
but it is a correct judge. 'Best', being a relative term, takes an idividual's
ideals into account, 'correct' being what is actual in practice.

The Best is chosen by the market that which is used to create the most
successful product. By that measure, PHP is the best because Facebook is
written in it. Best to the individual is much more complicated. The two will
rarely coincide due to the uniqueness of the individual and the typical
rejection of authority by intelligencia.

I would never say that PHP is the 'best' language for doing high abstraction,
but it can be done. I also would not use it for such things, but you said you
have (if you are the author of the article).

The 'Best' language is what you do _your_ best work in, whether paid or not.
Just don't expect to use it at work, and if you could, you would think
something else would is best and pine for that.

It's the job, not the tools.

~~~
mjburgess
facebook is not written in PHP, it's written in a PHP-like language developed
by them which is then transcompiled into C++ and then to binary.

> It's the job, not the tools.

Again, this is what i disagree with. There really is something objective,
independent, and "true" to be said about the utility of various languages in
various problem domains. There really is a language which represents the
problem space most accurately, for example.

It's just defeatism to suppose that "it's all the same, whatever works".
Innovation is, of course, the _opposite_ drive. It is at the innovative egdes
of programming languages that these debates are had. If you arent part of this
innovative edge then it may seem to you that the things youre using are just
"market decisions", they are _far_ from it. Every programming language you are
using has not been created by the market, it has been shaped by the very
debates i am talking about.

The market cannot create languages, it does not improve them, the market
merely plays out a baggage'd history which language-theorists have to cope
with. This is why PHP has changed so much: it is the force of the people who
engage in this discussion _on_ the market, to drive it towards "better".

~~~
kruhft
Facebook was originally written in PHP.

It's true there are awesome specific language tools for your specific
problems, that when tied together to create a total solution creates an
unmaintainable mess that even the creator doesn't understand.

Look at the web.

I saw Kerrnigan talk about 'little languages' and I fully agree that a
specific language designed to solve a problem is the way to go _for small
problems_ , like the ones when Unix was designed. Tying all these text based
interfaces together is a maintenace nightmare.

Maintenenace is a much bigger problem than the actual problems being solved,
at least for businesses.

Then there's Lisp, which is a mini-language designer's tool kit _and_ the
super glue to tie them together all in one integrated package using a well
designed, common binding agent. Unfortunately the market has choosen not in
it's favour.

The market will improve languages and in end game is that they'll all have the
same features, and then it comes down to syntax and performance. They'll all
be 'better' by today's standards. The problem is at that point is that the
better bar will have moved.

And the guy that truly innovated during that time won't be found until the
next century.

------
mjburgess
A Follow Up:

[http://blog.mjburgess.co.uk/2013/05/notes-on-systematic-
argu...](http://blog.mjburgess.co.uk/2013/05/notes-on-systematic-argument-
for.html)

------
mjburgess
I accidentally deleted the original submission.

------
michaelochurch
This is something I'm attacking right now. I'm undecided how far I want to
take the series, but this is Post #1:
[http://michaelochurch.wordpress.com/2013/05/06/constructing-...](http://michaelochurch.wordpress.com/2013/05/06/constructing-
computation-1-symbols-nonsymbols-and-equality/)

The starting point of this computation model is:

    
    
        1. There are symbols and nonsymbols.
        2. Symbols can be equality-compared (eq'd).
        3. Nonsymbols can be observed for behavior (in symbols returned) but not eq'd. 
    

The set of symbols is countable and includes:

    
    
        1. Natural numbers.
        2. Unique symbols for arbitrary "dictionary words", e.g. _error. 
    

Nonsymbols represent mappings that take nonsymbols or symbols and input and
return nonsymbols or symbols. That's not well-defined (and it's not even a
_set_ ) but we are only concerned with those that return symbols (i.e. can be
observed) after certain input patterns. For example, A : {_ => A} and B : {_
=> B} are both nonterminating but behave identically based on what we can
actually observe; it's meaningless to argue about whether they are "the same"
and since nonsymbols can't be eq'd, also unanswerable.

 _Code_ (as in source) is essentially a process that takes a natural number
(viewed as an array of _bounded_ natural numbers) and converts it into
something that _behaves as_ a nonsymbol, at least over inputs we care about.
Of course, there are many nonsymbols that we can't represent in code, such as
one corresponding to the Halting Problem,

    
    
        {$sym => 0, $nsym => 0 if exists k s.t. apply^k($nsym, 0) is a symbol,
         1 otherwise.}
    

Maps, vectors, and sets give us tools for describing extremely well-behaved
(finite support; returning _error on the not-found case) nonsymbols in code;
functions give us a language to describe well-behaved infinite-support
nonsymbols.

The neat thing about traditional functional programming is that it carries an
implicit will to focus on well-behaved nonsymbols. Object-oriented programming
hasn't stepped away from the full space of nonsymbolness-- and that's a big
part of why it's so damn hard to reason about it.

~~~
davesims
I like this as a more systematic starting point, with more direct application
than the high-level conceptual approach I gravitate towards.

One quibble -- I would prefer non-negative(!) terminology, i.e., what is a
"nonsymbol"? A collection? A monad? A duration? An event? A process? A
closure? Some category that encompasses all of these? If so, can we find a
positive semantic rather than negative?

>> Object-oriented programming hasn't stepped away from the full space of
nonsymbolness-- and that's a big part of why it's so damn hard to reason about
it.

Well, this gets back to the ancient problem of "The Third Man" and categories
in general, right? One must categorize and "contain" meaning, trap it in
language a moment in order for it to remain meaningful, but paradoxically the
external thing that it symbolizes is always changing, so it's always escaping
any semantic trap we set for it. This of course has practical (concurrent)
implications in software as well as the high-falutin metaphysical stuff Plato
was talking about.

These days I'm starting to wonder more about how we may not be using state-
machines quite as effectively, or as often, as we might -- changing
functionality more aggressively as the data changes, in order to move towards
a better analogy with the ever-changing "real world" that software is trying
to model. Might this be more self-aware starting place to integrate functional
and object concerns -- both of which are necessary?

~~~
michaelochurch
_One quibble -- I would prefer non-negative(!) terminology, i.e., what is a
"nonsymbol"? A collection? A monad? A duration? An event? A process? A
closure? Some category that encompasses all of these? If so, can we find a
positive semantic rather than negative?_

Good question. I tend to think of it as a stateless (I haven't added state to
the model yet, and there are myriad ways of doing it so I'm debating how to do
it) object. To _apply_ it to something (symbol or nonsymbol) is like sending a
message, and the result of the _apply_ is what it returns.

Nonsymbol is deliberately vague, meaning "we don't know what this is". We need
a context to make sense of it (e.g. observe _size, then if that's a natural k,
observe 0, ..., k-1; it it's not, it's not in the Vector context) and if it
doesn't play by the rules of a known context, we're screwed. We continue to
need context when we "array-ize" nonsymbols into natural numbers.

Nonsymbols are like functions; however, a function has a well-defined domain
and non-symbols don't. However, the only useful nonsymbols are "function-like"
in that some sequence of symbols and known nonsymbols will produce an
observable (symbol).

