Difference between revisions of "Lambdas"

From CSE231 Wiki
Jump to navigation Jump to search
(Created page with "Lambdas are one of the most recently-added features in Java, essentially allowing one to pass a function as an parameter to a method. The functionality provided by lambdas has...")
 
Line 31: Line 31:
  
 
This code would perform the way we would expect from the pseudocode.
 
This code would perform the way we would expect from the pseudocode.
 +
 +
Now let's try a more complex example. Let's try to recreate the ArraySum program using this method. The pseudocode for this program would look like this:
 +
 +
<nowiki>finish {
 +
 +
    async {
 +
        leftSum = 0
 +
        for j in [0, midpoint) {
 +
            leftSum += array[j]
 +
        }
 +
    }
 +
 +
    rightSum = 0;
 +
    for j in [midpoint, array.length) {
 +
        rightSum += array[j]
 +
    }
 +
 +
}
 +
 +
print leftTotal + rightTotal</nowiki>
 +
 +
For this program, we'd need to write two classes: one for the HjSuspendable object passed to the finish() method, and one for the HjSuspendable object passed to the async() method. There is an issue, however. Several variables need to be accessed both inside and outside of the async. The array, instantiated outside of the finish, must be accessible within both the finish and the async. The leftTotal and rightTotal variables, instantiated inside of the finish, need to be accessible outside of it. Because we're creating a new class, this can easily be accomplished by creating instance variables within our new classes. The code would look something like this:
 +
 +
<nowiki>class SumLeftHalf implements HjSuspendable {
 +
 +
    int[] array;
 +
    int midpoint;
 +
 +
    int leftSum;
 +
 +
    public SumLeftHalf(int[] array) {
 +
        this.array = array;
 +
        midpoint = array.length / 2;
 +
    }
 +
 +
    @Override
 +
    public void run() {
 +
        for (int i = 0; i < midpoint; i++)
 +
            leftSum += array[i];
 +
    }
 +
 +
    int getLeftSum() {
 +
        return leftSum;
 +
    }
 +
 +
}</nowiki>
 +
 +
<nowiki>class AsyncArraySum implements HjSuspendable {
 +
 +
    int[] array;
 +
    int midpoint;
 +
 +
    SumLeftHalf sumLeftHalf;
 +
    int rightSum;
 +
 +
    AsyncArraySum(int[] array) {
 +
        this.array = array;
 +
        midpoint = array.length / 2;
 +
    }
 +
 +
    @Override
 +
    public void run() {
 +
 +
        sumLeftHalf = new SumLeftHalf(array);
 +
        HabaneroClassic.async(sumLeftHalf);
 +
 +
        for (int j = midpoint; j < array.length; j++)
 +
            rightSum += array[j];
 +
 +
    }
 +
 +
    int getSum() {
 +
        int leftSum = sumLeftHalf.getLeftSum();
 +
        return leftSum + rightSum;
 +
    }
 +
 +
}</nowiki>
 +
 +
<nowiki>AsyncArraySum arraySum = new AsyncArraySum(array);
 +
HabaneroClassic.finish(arraySum);
 +
System.out.println(arraySum.getSum());</nowiki>
 +
 +
Note the incredible bulkiness of this code. This code is significantly longer than the pseudocode, and part of this stems from the fact that we are writing entire classes to contain methods. The other issue is that a method in one class does not have access to the local variables in another class. This fact requires us to create methods and fields to store and access these variables, making the code a lot less readable.

Revision as of 03:21, 1 February 2017

Lambdas are one of the most recently-added features in Java, essentially allowing one to pass a function as an parameter to a method. The functionality provided by lambdas has always been available, but lambdas allow the syntax to be significantly more succinct. This page will discuss alternatives to lambdas in order to better explain what lambdas are doing behind the scenes. It is based on the Java Tutorials, but has been adapted for the code used more frequently in CSE 231.

The Problem

In Habanero-Java, the async() method is used to spawn a task that will run asynchronously to the rest of your program. Ideally, the async() method would take a function as a parameter. The async() method could then call this function in parallel with the rest of your code. In Java, however, functions cannot be passed as parameters to methods. Only objects (and primitive types) can be passed in.

To solve this problem, the async() method takes an HjSuspendable as a parameter. HjSuspendable is an interface which contains a single method: run(). You have to pass in an instance of a class that implements HjSuspendable--thus guaranteeing that it has a run() method--and the async() method will call the run() method of your object asynchronously.

Separate Classes

A straightforward solution is to write your own class that implements HjSuspendable. Let's say, for example, that you want to print "Hello, World!" asynchronously. The pseudocode for this would be something like this:

async {
  print "Hello, World!"
}

We could create a class called PrintHelloWorld that implements HjSuspendable. It would look something like this:

public class PrintHelloWorld implements HjSuspendable {

    @Override
    public void run() throws SuspendableException {
        System.out.println("Hello, World!");
    }

}

An instance of this class could then be passed into the async() method. For example:

HabaneroClassic.async(new PrintHelloWorld());

This code would perform the way we would expect from the pseudocode.

Now let's try a more complex example. Let's try to recreate the ArraySum program using this method. The pseudocode for this program would look like this:

finish {

    async {
        leftSum = 0
        for j in [0, midpoint) {
            leftSum += array[j]
        }
    }

    rightSum = 0;
    for j in [midpoint, array.length) {
        rightSum += array[j]
    }

}

print leftTotal + rightTotal

For this program, we'd need to write two classes: one for the HjSuspendable object passed to the finish() method, and one for the HjSuspendable object passed to the async() method. There is an issue, however. Several variables need to be accessed both inside and outside of the async. The array, instantiated outside of the finish, must be accessible within both the finish and the async. The leftTotal and rightTotal variables, instantiated inside of the finish, need to be accessible outside of it. Because we're creating a new class, this can easily be accomplished by creating instance variables within our new classes. The code would look something like this:

class SumLeftHalf implements HjSuspendable {

    int[] array;
    int midpoint;

    int leftSum;

    public SumLeftHalf(int[] array) {
        this.array = array;
        midpoint = array.length / 2;
    }

    @Override
    public void run() {
        for (int i = 0; i < midpoint; i++)
            leftSum += array[i];
    }

    int getLeftSum() {
        return leftSum;
    }

}
class AsyncArraySum implements HjSuspendable {

    int[] array;
    int midpoint;

    SumLeftHalf sumLeftHalf;
    int rightSum;

    AsyncArraySum(int[] array) {
        this.array = array;
        midpoint = array.length / 2;
    }

    @Override
    public void run() {

        sumLeftHalf = new SumLeftHalf(array);
        HabaneroClassic.async(sumLeftHalf);

        for (int j = midpoint; j < array.length; j++)
            rightSum += array[j];

    }

    int getSum() {
        int leftSum = sumLeftHalf.getLeftSum();
        return leftSum + rightSum;
    }

}
AsyncArraySum arraySum = new AsyncArraySum(array);
HabaneroClassic.finish(arraySum);
System.out.println(arraySum.getSum());

Note the incredible bulkiness of this code. This code is significantly longer than the pseudocode, and part of this stems from the fact that we are writing entire classes to contain methods. The other issue is that a method in one class does not have access to the local variables in another class. This fact requires us to create methods and fields to store and access these variables, making the code a lot less readable.