I’ve spent the morning reading a tutorial about Haskell. At a glimpse, it looks like an aesthetically pleasing language that fits my brain pretty well. But that’s not the part that inspired me to write. Instead, I can’t stop thinking about the line between a language and its implementation.
There is no high-level language that frees you completely from the need to understand what the details of its implementation.
The interpreter reads a line of input from the user input device, which is then parsed for a word using spaces as a delimiter; some systems recognise additional whitespace characters. When the interpreter finds a word, it looks the word up in the dictionary. If the word is found, the interpreter executes the code associated with the word, and then returns to parse the rest of the input stream.
The basic data structure of Forth is the “dictionary” which maps “words” to executable code or named data structures.
The compiler itself is not a monolithic program. It consists of Forth words visible to the system, and usable by a programmer. This allows a programmer to change the compiler’s words for special purposes.
In most Forth systems, the body of a code definition consists of either machine language, or some form of threaded code.
Maybe the conclusion is that abstraction requires assumptions? And I prefer that assumptions be made explicitly. But you can never make all assumptions explicit. (Draw the rest of the owl.)
Maybe the conclusion is that language, not just programming language, is an inherently leaky construct. If every word is defined in terms of other words, where does the recursion stop, except in the minds of the speaker and the listener. Hopefully the speaker and the listener have the same impression of what the words mean.
I’m reminded of about the AMA between Alan Kay and Rich Hickey. Alan Kay said something along the lines of “For important messages, you don’t send the message alone and hope the message is interpreted correctly. You send the emissary along to ensure that the message is interpreted correctly.” * Compare and contrast the C/Unixy way where you exchange relatively homogeneous messages and let each program interpret it how it wants. The message enables you to decouple one program from another by letting them each do whatever the heck they want with it. * In the dumb-emissary (implementation) approach, the message (program) must be unambiguous and thorough.
The line between a message and an underlying assumption is fascinating beacause, I think in natural language communication, most people don’t realize when they don’t have a concrete understanding of a word. The whole “context clues” thing is a double-edged sword.
The question of “if every word is defined in terms of other words”, maybe it ultimately boils down to patterns established in the speaker and listener’s minds in terms of context clues. The danger is that they have been exposed to a different set of experiences and likely have different context clues.
Hemmingway’s six word story is potent precisely because of the patterns, our ability to infer the rest of the story, and the universal nature of the tragedy that it implies. * This is an instance of a small message, with a “smart” emissary. Hemmingway wrote a concise and powerful message because he knew how readers would interpret it.
Do I have different preferences for code and literature? No. Actually, I like prefer concise code too. But I don’t like it when there’s a leaky abstraction that I can’t get at. * The art, then, is knowing what needs to be made explicit and what can be left as an assumption between the speaker and the listener. Know your common axioms.
How?