I think I’m going to go back to programming in APL and Lisp. The concepts and methodologies of decades ago are being reborn in today’s languages, like Microsoft’s C# and Sun’s Java. Of course, languages like C#, C++, and Java were designed to take advantage of other object-oriented precursors such as Simula and SmallTalk.
However, in trying to minimize the complexity of the new languages, designers left out many features. Some of these features found their way back into the new languages through runtime support or extensions that can be added within the language’s normal extension mechanisms.
Yet in many cases, a fundamental change is necessary to the syntax or semantics. These types of changes aren’t taken lightly, since they can break existing applications. Still, enhancing a language this way can have a major impact on developers in areas such as efficiency and code quality.
I Say Tomato, You Say...
Lisp is built around lists and lambda expressions. Lambda expressions are closures that include any bound variables at the time the closure is created. Take this short interactive Lisp session:
> (define timesN (lambda (N)
(lambda (x) (* x N)))
> ((timesN 4) 3)
The timesN variable is assigned a lambda expression that takes a single parameter. It returns another lambda expression that also has a single parameter. The difference is that the inner unnamed lambda expression references the N parameter.
The first parameter of a list being evaluated in Lisp is the function to be executed. This works recursively so the second statement executed in the example evaluates (timesN 4), which returns a lambda expression that will multiply its parameter by four. In this example, it is applied to parameter 3 with a result of 12. As shown, lambda expressions are first-class values that can be stored and passed as parameters.
I Say Delegate, You Say...
C# 2.0 introduced the concept of anonymous methods, which allowed the creation of method definitions without names that are common in the callback approach commonly used throughout Microsoft’s Windows operating system. This was more shorthand than a radical semantic enhancement because the same thing could be done, albeit with more textual decorations.
C# 3.0 adds explicitly or implicitly typed lambda expressions to the mix. In the latter case, the types are inferred from the surrounding code context. The syntax is simpler as well.
(int x) => return x * 4;
Similar closure functionality is being considered for Java 7.
From a C# or Java developer’s point of view, enhancements like lambda expressions are favorable additions. Their implementation may lack the elegance and consistency of Lisp since the new features are tacked on rather than part of the original language definition. But, elegant or not, they will get a lot of use.
So what about C and C++, since they’re used in the bulk of embedded applications? Callback functions are already the norm, but two issues crop up: syntax and garbage collection.
Syntax is arbitrary since there is no standard. C macros and C++ class definitions can hide this, though an implementation may have to deal with ugly issues such as casting void* pointers.
Memory allocation is more problematic since the memory must be explicitly deallocated. C++ has the edge over C here. With C++, though, developers still need to deallocate the closure. Either way, the solution isn’t very elegant.