Monday 12 May 2014

Java 8 is functional, and fun

When I heard that Java was getting 'lambdas' or, as I prefer to think of them, sort-of-closures, as I was an enthusiastic Smalltalk programmer many years ago, I wasn't that excited.  Being Java, I thought that these lambdas would be dull but reliable, which is what I have come to expect of Java.  I had no complaints, because Java is all about solid, reliable, readable code.  I was mistaken - Java lambdas are extremely powerful and huge fun.

What I really love about Java 8 lambdas is the ability to have them implicitly constructed by method references.  That sounds obscure, but it's one of the most powerful and expressive features of Java 8.

I'll show how this works by showing some Smalltalk code.  This code might be from some sort of user interface, and maps key presses to code.

codeMap := Map new.
codeMap at: $A put: #doThis.
codeMap at: $B put: #doThat.

$A and $B are character constants.  #doThis and #doThat are symbols, which in this code hold the name of methods. So, the following code will work:


onKeyPressed: key

keyHandler perform: (codeMap get: key)

The symbolic method name is looked up using the character supplied and the object 'keyHandler' is passed that method name to run.

It's a very concise way of mapping characters to functions, without the need for hard-coded and verbose 'if' or 'switch' statements.

This was impossible in Java.  Until Java 8.  Now, it's very easy.  Here is an example:

public class KeyHandler {

// Map of  Character to a function which has a single parameter - a KeyHandler Instance

public final static Map<Character,Consumer<KeyHandler>> codeMap = new HashMap<>();

// Put method references into the map
static {
   codeMap.put('A',KeyHandler::doThis);
   codeMap.put('B',KeyHandler::doThat);
}


// The map can be used like this
public void respondToKey(char key) {
    Consumer<KeyHandler> function = codeMap.get(key);
    if (function != null) {
        function.accept(this);
    }
}

private void doThis() {}
private void doThat() {}
}

What's going on here is that Java 8 lambda syntax means that the map construction could have been done like this:

codeMap.put('A', (KeyHandler handler) -> {handler.doThis();});
codeMap.put('B', (KeyHandler handler) -> {handler.doThat();});

The type of 'handler' can be inferred because of the type of codeMap, and single statement lambdas don't need brackets:

codeMap.put('A', (handler) -> handler.doThis());
codeMap.put('B', ( handler) -> handler.doThat());

brackets aren't needed for lambdas with one argument:

codeMap.put('A', handler -> handler.doThis());
codeMap.put('B', handler -> handler.doThat());

These lambdas are treated implementations of the interface Consumer<KeyHandler>.  In Java 7 this code could be written using inner anonymous classes:

codeMap.put('A',new Consumer<KeyHandler>() {
   public void accept(KeyHandler handler) {
       handler.doThis();
   }
});

And so on.  There is the slight matter of the 'Consumer' interface not being available in Java 7, but that doesn't matter for this example.

Java 8 lambdas are much more concise, and, it turns out, can be run-time optimised to be typically much more efficient than inner classes, both in terms of memory and speed.

We are nearly there with explaining the use of method references.  In Java 8 a method reference can be used instead of a lambda if the method is, if renamed, the same as the single method in the interface that the lambda is an instance of.   Well, almost.  Assume it is the case for now.  Suppose we had a method that wanted a Runnable as a parameter:

public void doThing(Runnable runnable) { runnable.run(); }

The KeyHandler methods doThis and doThat have no arguments and no return value, and so they are the same as the Runnable method run().  And so, in Java 8, references to these methods can be used as 'Runnable' instances.

KeyHandler handler = new KeyHandler();
doThing(handler::doThis);

Any method that has no arguments and no return value can be used as a Runnable instance in Java 8.

There is one final step to explain what is going on in the KeyHandler class.  Java 8 can have method references even when there is no instance of the class implementing the method.  There is an obvious case of when this is needed:  static methods.  Static methods aren't run by instances.  Here is an example:

public class Thing {
    public static void printSomething() {
        System.out.println("Hello");
    }
}

The method Thing.printSomething() has no arguments and returns nothing, so it can be used as a Runnable:

doThing(Thing::printSomething);

This will print "Hello".

Now let's give Thing an instance method:

public class Thing {
    public static void printSomething() {
        System.out.println("Hello");
    }
    public void printSomethingElse() {
        System.out.println("Goodbye");
    }
}

What does "Thing::printSomethingElse"  mean?  It's an instance method, but no instance is given.  It has no arguments and returns nothing, so it looks like a Runnable.  It isn't.  There is a hidden argument in this method reference.  That hidden argument is the instance that will run the method.

Thing:printSomething else, is, in fact a possible implementation of Consumable<Thing> (or any other interface with a single method that takes a Thing as parameter and returns nothing).

This is how this method reference can be used:

First, we define a new method:

public void doThing(Thing instance,Consumable<Thing> function) {
    function.apply(instance); 
}

Now we use it:

Thing instance = new Thing();
doThing(instance,Thing::printSomethingElse);

This will print "Goodbye".

Finally, we can see what the method references are all about in the KeyHandler class.  They indicate what instance methods are to be used, and also that an actual instance must be supplied.  That's why they are effectively Consumable instances and not Runnable instances even though the methods they refer to have no arguments and return nothing.

So, I finally get to code my Smalltalk idiom in Java!
 

Tuesday 6 May 2014

Why not Scala?

Scala is a very powerful and relatively new language that runs on the Java runtime - the "Java Virtual Machine" (JVM).  It's getting a lot of positive publicity, and it seems that it is gaining acceptance.  However, I'm really cautious about using it in any major project that is expected to be run and maintained for years.  Why?  There are many reasons, here are a few:

1. Complexity.

Scala is BIG language.  It combines object-orientation with functional styles and seems to include almost every possible thing that a programming language can do.  Some (far from all) the programming idioms currently in Scala (2.11.0) are:

declarative matching
case conditions
case classes
value classes
'for' comprehensions
xml embedding
dynamic method calls
generics
type range syntax
implicit methods
implicit classes
parameter placeholders
method references
special 'apply' method
currying
tuples
destructuring binds
traits
relative imports
package objects
named arguments
partially applied functions
lazy values
type aliasing
'operator' overloading

I have been programming and keeping up as best I can with programming for over 30 years, and, to be honest, I'm not sure what a few of these mean.

I do like many of these features: Implicit methods are a neat way to add functionality to existing classes by invisibly transforming such classes into new classes with new functions:

// Here is a silly example

class MyString {
def hello {
    println("hello")
}

implicit def toMyString(s: String) = new MyString

// Now "abcd".hello will print "hello" - effectively a new method .hello has been added to all strings where 'toMyString' is in scope.

However, this ability to tweak what code can do in hidden ways can lead to source that is extremely hard to follow.  Also, what can be done by a developer will end up being done by someone in a development team if that team is of any but the smallest size.  I know from experience.

2. What does Scala code do?

Here is an example of normal Scala code:

val x = myFunction()

What is going on here?  All we can see is a function call.  What kind of thing is 'x'?  What can it do?  The problem here is that Scala can infer types based on whatever is assigned to a value or variable.  You could write:

val x: String = myFunction()

Assuming, of course, myFunction returned a String, but this isn't necessary, and inference of type is standard practice.  But, if someone changes the return type of myFunction() at the point of its definition, you may have no idea that this has happened until a program has been run.  Look at the following code:

def getMyValue() = 1

val result = getMyValue() + getMyValue()
println(result)

When run, this will print "2"

Now, change the function:

def getMyValue() = "1"

When run, this will print "11"

Type inference is an example of where I think Java is doing things the right way.  Java insists on the type of a variable being described when the variable is defined:

String x = myFunction()

Any change in the result type of the function will be immediately caught at this point in the code by the compiler.  Java 8 allows for type inference to be used to reduce the amount of code needed to describe lambdas. 

Java 7:

Runnable code = new Runnable() { public void run() { System.out.println("run!"); }};

Java 8:

Runnable code = () -> System.out.println("run!");

That the lambda (the bit after "=") represents a Runnable, and the code should be seen as the body of a "run" method is inferred from the type of the variable "code". 

Java has the contract between function developer and function user explicit at the point of use.  This leads to clearer code.

3. Scala changes.

You can run positively ancient compiled Java code on the most modern Java VM.  a Java GUI program written from the early days of Java will still compile, and still run.  Java code doesn't die.

Scala is younger, and already a significant part of the language and libraries - the Actor system for parallel code - has been deprecated and replaced by a newer library, resulting in the need for migration work.  The new library (Akka) is a great system, but developers of significant and long-term projects really don't want to have to face this kind of change to keep up-to-date with bug-fixes and new features.  At least I don't!  Java's slow adoption of new idioms can be a real advantage for this kind of development, where stability is vital.

4. Who uses Scala?

In spite of it's frequent discussion, the actual use of Scala seems to be very small.  The TIOBE site monitors the volume of information on many Internet sites about different languages.  As expected, Java and C dominate.  Over recent years JavaScript and Objective C have grown hugely.  Scala is down below the decimal point of a percentage, somewhere between Fortran and Prolog. This does not directly indicate the quality of Scala, but it does show that getting Scala developers for a major project can be difficult and expensive.

It could be justifiably said that I'm not helping Scala with this attitude.  But I have to face the fact that software development for large and long-term projects isn't about taking a charitable approach to development languages and tools.  It's about delivering stability, reliability, and long-term maintainability.  It's about being justifiably dull!

Saturday 3 May 2014

Why Java?

I have been a programmer most of my life.  I fell in love with programming as a young teenager.  I learned BASIC, because, then, everyone learned BASIC.  I progressed through Fortran, Algol, COBOL, and various assemblers... but that was decades ago.  Now I program mainly in Java, with occasional use of Scala. 

Java has a reputation of being clumsy, boring and out-of-date.  That's wrong.  Java has changed the way programming is done, and for the better.  Java has been around a long time, and it's worth looking back to how most programming was done at the time Java appeared.

The most widely used development languages were C and C++, and they were used for all kinds of development projects, from the writing of hardware drivers to office software and databases.  It's possible to program clearly and robustly in C and C++, but it's also very easy to end up making disastrous errors.  The reason why errors are so easy is because C/C++ provides a recipe for pretty much direct use of hardware.  What seems to the programmer to be abstractions are in really nothing more than conveniences of syntax - making raw use of resources look structured.  An example is C arrays:

int store [100];

This looks like an array of 100 integers, but it's not really.  It's simply an area of memory that your program now knows about.  It C it's perfectly acceptable to refer to the 200th element of 'store', and even to write data into it.  C compilers can be set to check for this kind of thing, but that's not part of the language.  Compare this with Pascal

var store: Array 1..100 of Integer;

The compiler and program know what this is: an array of integers.  Try and access store[101] and you will get an error. 

Pascal is C with seatbelts.  It can be much safer because restrictions on what can be done can be designed into the language, and many dangerous operations can be checked at compile time, even though they will also result in safe reporting of a mistake when the program is running (although, to be fair, such checks can be turned off to improve program speed).

C/C++ has been a disaster for software safety and security.  It's use is the primary reason why we suffer from computer viruses and security holes. 

Another real problem with C/C++ is portability.  Compiled programs are almost always limited to one type of computer, and one operating system.  Write a C program for Windows and you aren't going to be able to run it by default on MacOS/X or Linux.   This is a real problem, as there are countless legacy systems written in C/C++ that cannot be moved to modern platforms as it would be too expensive to re-write them.

There were many portable and safe languages around at the time Java was invented - LISP and Smalltalk, for example - but these didn't make an impact on C/C++ development because they were so different in style.  Java copied C/C++ syntax so was relatively easy for developers to pick up. 

Java provided safety, in that it had a carefully managed and garbage-collected memory management, and there were many layers of security built-in, so that use of resources on a machine had to be carefully approved for code that was delivered over the network.  This hasn't always worked, but it's always been far safer than the C/C++ approach. 

But, best of all, Java was extremely portable.  Today, I routinely develop and test Java applications on Windows for deployment on Linux and Solaris, and there are no platform-specific problems.  This has made transition to modern 64-bit machines effortless - I haven't had to do anything but download 64-bit versions of the Java runtime.

When I have worked in a programming team, Java has been extremely useful because of the clarity of the syntax: code is not subject to the obfuscation that can be achieved in C/C++ through the use of macros and operator overloading.  Java syntax may look simplistic, but its explicitness is valuable.

Finally, Java has managed to combine safety with very high performance.  The 'hotspot' automated run-time compiling and tuning technology means that none of the traditional ways of manually optimising code are necessary, and instead developers can concentrate on clarity and functionality. 

Java's compatibility includes the ability to continue to run ancient (in IT terms) code on modern Java runtimes.  Java is one of the safest languages to use if you expect to be supporting an application for a decade or two, without the need to recompile all your applications.

 Java 8 allows for functional programming, increasing the power of Java to make use of parallel processing, with all the automation and safety that is typical of the Java language.

Java may not be the most elegant language, but it's status one of the most widely used (if not the most widely used) language is richly deserved.