19. Misc Topics

Part of CS:2820 Object Oriented Software Development Notes, Fall 2015
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

 

Lambda Binding Is Not So Simple

Officially, lambda binding is supposed to be equivalent to creating an anonymous instance of an anonymous subclass, so:

Simulator.schedule(
        t + travelTime,
        (float time) -> this.exit( v, time )
);

is supposed to be equivalent to:

class MyAction implements Action {
        void trigger( float time ) {
                this.exit( v, time );
        }
}
MyAction act = new MyAction();
Simulator.schedule( t + travelTime, act );
This is not quite the case. If you use lambda binding, the compiler forces your hand. Specifically, local and class variables referenced from within the expression in the lambda binding must be final or effectively final. That is the compiler must be able to prevent additional assignments to those variables. As a result, this code from Lecture 16 (Oct 22) is illegal:
v = vehicle1;
Simulator.schedule(
        t + travelTime,
        (float time) -> this.exit( v, time )
);
v = vehicle2;

Java does not permit changing the binding of v after using v in a lambda expression. On the other hand, attributes of v can be changed (if it has any) so the warning still holds. It is just that this is a bit more subtle than the illustration in the notes.

A Bug

The assignment for MP4 requires that your simulation terminate when there are no more pending events, but the simulation framework originally provided offered no way for class Output (the new class you are writing) to do that. Oops. This has been rectified by adding the following new method to class Simulator:

static boolean moreEvents() {
        /** Report if there pending and not yet triggered events.
         */
        return !eventSet.isEmpty();
}

So, you can now call Simulator.moreEvents() to ask if there are any more pending events, allowing your program to cease scheduling new output events when it finds that nothing more will happen.

A Small Programming Pattern

Since the only code you are turning in is in the file Output.java containing the class Output, a subclass of class Gate, you face some problems. One of them is to figure out how to schedule the first output event when there is no code in the main program to initialize this.

If the logic circuit contains any output gates, however, there is code in the main program to call Output.scan() once for each gate. So, you can write Output.scan() to do the initialization on its first call.

A relate problem arises from the need to print the list of all output names as a header in the output of the program. This header needs to be printed exactly once, yet there is no specific method to print this header. Instead, you will have a method scheduled once per time unit to print the outputs, and you can make this method print the header the first time it is called.

There is a programming pattern you can use to solve both of these problems:

// flag to control a thing that must be done just once
private static boolean needed = true;

// method that will do the thing just once
Example method() {
        if (needed) {
                DoThisJustOnce();
                needed = false;
        }

        ... // remainder of method
}

This pattern can be applied in many contexts, and it is just one example of a programming pattern. There are many other such patterns that you know (without necessarily calling them patterns). For example, the discrete-event simulation pattern we are using for the road network and logic circuit examples is a very big pattern, but you also know some very simple patterns, for example, how to use a for loop to sum an array.

Sometimes, this pattern will be used with an explicit boolean control variable, but in other cases, you will find that some other variable will serve to control it.

For example, your Output.scan() method is going to have to build a list of all output gates -- each time output is printed, the print method will have to traverse the list of output gates. Printing the list of output names will also require traversing this list. Initially, this will be an empty list, so you can use the List.isEmpty() method to detect the first call to your Output.scan() method.