A canyon size flaw in at the heart of C# and Java.

Gorge Du Verdon

C# and Java are starting to show their age. Here is one example at the most fundamental level of these two languages.

Both C# and Java inherit a lot of their syntactic and semantic structure from C. However, they enforce a very different programming paradigm than that in which C is normally written. This forces C# and Java to be asymmetric and flawed in a way which causes constant trouble, considerable performance issues (especially for Java) but which is not seen by most developers due to them not having realised that alternatives exist.

Let us first consider C. One of the key linguistic components of C is the function. The C standard library is all based on functions and any non trivial C program is full of them. A C function is based conceptually on a mathematical function and consists of three parts:

This is perfect for functions which are quite mathematical in nature. However, software engineering involves a lot of data manipulation as well at algorithm development. This generates a requirement for function like entities which pass out more than one data item. A classical function only has a single return item. In essence, function entities in programs often need to have polyadic returns where as C functions have a unary return.

The most common paradigm for managing polyadic returning functions in C is to pass parameters in by reference. Thus, the parameter list contains part of the return as well as the input. This works rather well in C because, for these non mathematical style functions, the return value its self is used as an exception handling mechanism. Indeed, in early versions of C, the return was often defaulted to an integer type and could be omitted from the declaration. In other words, the notion is that the main communication with the function is through the arguments. The return from the function is zero for all non exceptional circumstances and non zero in the exception case. C support arguments by reference via a very light weight syntax and so this approach works well though it is a little clunky.

Both Java and C# have a build in exception handling system. They do not require the return from a function to return this meta information. So, why do they have return values at all? Whilst return values are handy they are not required. Consider the following Java:

class A
{
    public MyClass myObject;
}

class B
{
    public void myObjectFactory(A ret)
    {
        ret.myObject=new MyClass();
    }
}

With this we can pass MyClass objects out of a method without using a return. Using the 'ref' modifier in C# makes this even easier in that language (we do not require the A class). However, the use of return values rather than communicating only through the arguments feels more comfortable and avoids creating container objects in Java. Nevertheless, by retaining the C like single return value, C# and Java are left being asymmetric. The paradigm is to pass stuff in through the arguments and out via the return. However, there are many arguments (polyadic) but only one return (unary).

A much cleaner syntactic solution would be to make functions polyadic in both arguments and return. An example could be:

(int,int) quotentAndRemainder(int num, int den)
{
 return (num/den,num%dem);
}
// which could be called like this
int q,r;
(q,r)=quotentAndRemainder(23,5);
// here q=4 and r=3

Such an approach allows a cleaner implementation of the concept of references and arguments. One does not need to pass in references just to allow 'out parameters'. References would only be needed in multi-threaded applications where the state of a variable inside a function needs to be known during the execution of that function. As that programming model could be considered to be bad practice anyway, polyadic returns could eliminate the need for references in all but the most obscure situations.

The syntactic structure of C# and Java would not permit this simple implementation of polyadic returns; however, I hope it is clear how useful they would be. The more interesting (to me) point is that this issue in the languages shows how they are not the final evolution but just another stepping stone in the long path leading to a fully useful language. Indeed, their strict unary return structure and terse syntax locks them out of being evolved to accommodate better semantics in the future.