March 2009

Language Aspects

Introduction

Constant Factor

Real World Usefulness

Language Expressiveness

What is a Feature?

Aspects

Rich Arithmetic

Hides the complications of converting between various number representations and their precisions. For example, the language can handle the promotion of int32 to BigNum, or provide the square root of negative one. Although operator overloading can achive the same effect, having this feature built-in saves time.

Object Orientation

The ability to group variables and code into one logical entity for conceptually cleaner programs. Even though OO techniques can be used in almost any language, there are minor advantages to formalizing those methods, and forcing them to be adhered to. Closures achieve some of the OO objectives.

Properties or Annotation

The ability to add and remove properties from individual objects irrespective of the class to which they may belong. This is easily in prototype-based languages, like Javascript, but can also implemented with multiple instantiation, or mixins, in class based OO.

Without properties, using generic get and set methods:
    int age=person.getValue("age");
    person.setValue("age", age+1);
Without properties, using a map or dictionary:
    int age=allAges(person);
    allAges.setValue(person, age+1);
With properties:
    person.age++;

Vectors/Tuples

There are enough small, fixed length, lists to warrant special syntax, we will call thenm vectors, or tuples. The benefits are:
  • Multiple-value method returns:
      [result, remainder] = divide(a, b)
  • Sucinct list initialization:
      List myList = ['maple', 'ash', 'walnut']
  • Swap values:
      [a, b] = [b, a]

Inheritance

In a typed environment, inheritance is a conceptually easy method for reusing code by programming differences.

Elegant Null Handling

No matter the language, you will have to deal with null return values*. There should be a succinct way of dealing with nulls, if only because of how common they are. Null return values could emit exceptions; defering null handling to the exception handlers. Also, special syntax, or a function, should indicate null value checks: Smalltalk has "ifNotNil:", SQL has "nvl()". There should be short syntax for the following common situations:
  1. if (a==null) return null;
  2. if (a==null) throw new NullPointerException();
  3. if (a!=null) doRestOfWork();
*(This includes thrown exceptions and the trivailly different Null Objects).

Multi-line Quotation

The ability to quote multiple lines of text, wihout the need to escape the LF character.. This allows the language to quote other languages (like SQL statements), but also allows one to format text in general. It is unclear to me how the indentation of the quoted text relates to the indentation of the code which quotes it.

More than One Quote Symbol

Javascript uses two symbols for quotation; the single and double quotes. As long as they are paired properly, they are completly interchangable. This is a good feature because it allows quoting of quotes, and using one language in the quotes of another. For example: SQL uses single quotes for string constants; and quoting SQL in Javascript's double quotes avoids having to escape the single quotes. Perl can quote with q{}

Regular Expressions

Always helpful to match strings

Dynamic Dispatch

This reduces the work in reusing code via inheritance. In a high level way, the function inheritance uses covariant method specialization to eliminating the logical inconsistencies that would otherwise occur in a program specification. Single dispatch is considered inferior.

Garbage Collection

Generally, GC is used to reduce the manual work of handling heap memory. Languages that are pure functional, or demand linearity, automatically gain a point for having GC.

Keyword and Optional Parameters

How often have you known the parameters that a particular function requires, but forgotten the order in which they must be sent? This happens to me often, and when I get it wrong it can be a heinous bug to track down. Keyword parameters can solve this problem with no slowdown to the compiled code. A language could implement strict keyword parameter function calls, but it would be better to implement both positional and optional parameters.

Set Operations

Permits operations on sets. There is limited benefit to implementing something similar to "forAll x in y", or something like the Lisp LOOP macro. Even better would be to implement a relational algebra. Best would be to abstract away all conventional loop structures.

List Operations

A library of high-level list operations. This is used most for string processing, but does have value for lists in general. This is different than Set Operations in that lists are ordered, and there are specific operations that can take advantage of that order. For example, my personal favorite, last(a,n) - which takes the last n elements from a, or lastBut(a,n) - which takes the end of list a, except for the first n.

Dynamically Typed

Allows for the omission of explicit function/variable types when unnecessary. Dynamic typing allows the programmer to save keystrokes and stay deliberately vague in the event that the meta object system changes. An example of deliberately vague can be seen in the function
    printSum(a, b){
        System.out.println(add(a, b));
    }//printSum
which depends on the definition of add. If add is enhanced to handle complex numbers, then so too is the printSum function with no changes required.

Strongly Typed

Strong typing has the benefits of compiler optimization and compiler consistency checks. A language can still be strongly typed while being dynamically typed.

Asserts and Static Types

Static types are only a special case of dynamic asserts which a good compiler can identify failure at compile-time. With this in mind, all static types should be optional, just like asserts need not be written.

Polytypic Programming

When types are first-order objects, polytypic programming allows functions-acting-on-types and types-of-types. Haskell supports this very well. J2EE is painful because it lacks this feature. Polytypic programming subsumes generics.

Higher Order Functions

This allows references to functions (aka function delegates), but also reflection into their parameters and code.

Inline Methods (Closure)

When a second order function requires a method as a parameter, it is sometimes convenient to provide the whole method declaration in-line instead of declaring a separate method and using it's name. This is usually only useful with short methods; longer methods will distract from the function call being declared.
    add example here
The benefits of closures are:
  • Saves effort by not requiring a name
  • Keeps code syntactically localized, so all relevant code is on the same page.
  • Provides access to local variables, which would otherwise need to be method parameters to be accessed inside the method body.

Partial Evaluation

This allows the programmer to pass partial parameters to a function to produce a new function. Haskell has fairly good syntax for a specific version of PE, called currying. For example, we can define a function, g(), that always adds 3 to the parameter passed by using f():
    f(x, y) = x + y
    g(x) = f(x, 3)

Transactions

This is the ability to declare atomic sections or transactions. Whether implicit or explicit transactions are more useful depends on the problem domain. Transactions should nest neatly. In the event of an error a rollback is executed, the erred transaction state should still be available for introspection by the exception handler.

Meta Programming

The language has some built-in "execute" function where text is interpreted as code for execution. This facilitates second-order programming; code that writes code.

Macros

The ability to change the syntax or semantics of the language through a relatively simple interface. Of course the ability to change the semantics of a language requires others to learn those changes in order to understand your code. This is probably no more difficult than learning a library function. Macros appear to combine the concepts found in formal languages with the simpler concept of function libraries.

Pass by Value Semantics

Removes pointer complications, needs strong typing to "know" what is the value to pass. Functional languages naturally have this property.

Recursion Semantics

Recursion semantics are semantic brevity for recursive problems and data-structures. This is a necessary small domain, mostly limited to mathematical problems, but when used, recursion semantics enable the compiler to generate lazy code. This frees the programmer from having to implement the laziness himself, and simplifies code considerably.

Simple Semantics

Source code reflection is made easier when the semantics of the language are simple. There are two ways to achieve this aspect:
  1. Strictly simple semantics. Of course, simple semantics may reduce a language's semantic specialization; limiting its expressiblity in other areas. Lisp uses second order functions and macros to increase expressiblity despite simple semantics.
  2. Make a simpler intermediate language. This more complex, but provides an opportunity to have both the semantic efficiency of a high level language along with the simple reflection routines for a low level language.
A point is given if the number of primitive operators does not exceed 5.

References

Document History