Puns require both a talented author (to create the pun) and a talented reader (to understand the pun). I admit to missing one of Shakespeare's meanings the first several times I read Richard III's opening lines. As with all linguistic constructs, it offers benefits and costs. Those must be weighed in each potential use case.
Puns are not unique to natural language. They exist in optical illusions such as the Necker Cube. Many programming languages allow sufficient, intentional ambiguity for productive puns.
Dynamic Type
Consider the following JavaScript function which adds elements of a list to an initial value.One can invoke the function with integer, float or string values and obtain useful results. Dynamic types and an overloaded
+
operator provide the necessary ambiguity. This single function definition gives three useful procedures as a result. Most statically typed languages prohibit this pun by requiring type annotations on variables and parameters.A talented JavaScript engine might compile the above code into completely different machine language depending on the context in which it's used, the values available at runtime and the processor architecture on which the code is running. Just as natural language puns require a talented reader, programming language puns require a talented compiler.
Dynamic languages like Erlang and Dart embrace the ambiguity of dynamic types by adopting smart tools like dialyzer and dart_analyzer, respectively.
Parametric Polymorphism
Most functional languages let one write a generic map function like this:The function is a pun with meaning across all list types. The compiler infers types where necessary to ensure safety. The absence of type annotations provides the necessary ambiguity, so dynamic languages support similar puns, although without compile-time type safety assurances.
Java and C# allow similar puns with generics.
Logic Programming
Languages like Prolog and Mercury offer puns through ambiguity in constructors and pattern matching. For example, a singleappend
definition creates procedures for combining two lists to make a third, removing a list prefix, removing a list suffix and generating all combinations of two lists which, when combined, produce a third:One can use similar constructs to create punning predicates that split/join strings, parse/serialize data structures, etc.
In Mercury, goal order is unimportant which allows further puns in which the compiler reorders goals to achieve higher performance, lower memory usage or automatic parallelism. In each case, a single textual definition provides multiple procedural meanings.
Futures and Laziness
There's a related class of puns in which meaning is the same but a programmer is intentionally ambiguous about an important implementation detail. For example, Alice ML provides futures for the results of concurrent computations. In Alice, a future is syntactically identical to a variable. When one writes a function of a variable, it works on values, completed futures and incomplete futures. This lets APIs change their internal implementation with respect to concurrency without breaking encapsulation and gives the compiler freedom to schedule concurrent threads as it sees fit.Haskell's pervasive laziness is in a similar vein. A variable could represent a value or a thunk which, when needed, computes a value. A single function definition handles both. Mailing list threads about overcoming Haskell's laziness remind us that in some cases ambiguity is a pun too far.
Psychology of Puns
Most software developers have strong aesthetic preferences about their languages and tools. Witness the vi-emacs wars, endless debates about semicolons or brace placement and arguments about static vs dynamic typing. In these scenarios, there is no right answer. There are only programmers more or less comfortable with various constructs.Programming language puns and their linguistic ambiguity are no different. In this case, psychologists even have a name for it: ambiguity tolerance. Some people want firm rules and an environment that resolves into clear, precise answers (One True Way). Others thrive on uncertainty and broad choices (TMTOWTDI). Programmers bring this psychology with them when they design and choose languages.
Fortunately, I think there's room for compromise. By making certain language constructs optional and relying on smart compilers, programmers can either be ambiguous or precise, depending on their preference. The language can stay with them as their preferences evolve. There's a lot of interest in optional static typing (Perl 6, Python, Newspeak, Dart, Erlang, etc). I'd like to see further exploration of optional annotations and compilers that can usefully resolve programming puns.
No comments:
Post a Comment