Suppliers and Lambda Expressions
Let’s say you have a command and you want to provide it with input from a joystick. A common use case is for some kind of drive command, as a joystick can be used to control the speed of the robot. If you’ve never used lambda expressions, you might be tempted to pass in the joystick input by directly calling getRawAxis
to get the joystick data like this:
// If we aren't doing anything else, drive
m_driveSubsystem.setDefaultCommand(new DefaultDriveCommand(m_driveSubsystem,
m_controller.getRawAxis(0)));
However, all this does is call getRawAxis
when the command is constructed at startup. The method will get called and return a number, but that number won’t ever change. So using your joystick won’t do anything because the command has no way of obtaining the joystick state after it’s constructed.
To solve this, we use lambda expressions or anonymous functions. They act like normal methods, but without the boilerplate of declaring a method or a name(hence anonymous function.) We use them like a wrapper around normal methods to allow a normal method to be called at a later point. Here’s the previous example, but a lambda expression is used instead:
// If we aren't doing anything else, drive
m_driveSubsystem.setDefaultCommand(new DefaultDriveCommand(m_driveSubsystem,
() -> m_controller.getRawAxis(0)));
Now, getRawAxis
won’t get called until some code in DefaultDriveCommand
calls it. When it does call it, it will get the current state of the joystick, which can be used to move the robot.
Using the lambda expression in a command
A command’s constructor must have a Supplier
as one of its parameters to accept a lambda expression. A Supplier
has a get
method that can be called, returning a value with the type specified in the Supplier
. So when you construct a command and include a lambda expression as one of its arguments, the command can call get
on the variable storing the lambda expression to retrieve its current value.
Example
public class DefaultDriveCommand extends CommandBase {
// We store the supplier here so all methods can access the supplier
private final Supplier<Double> m_forwardSpeed;
private final DriveSubsystem m_driveSubsystem;
public DefaultDriveCommand(DriveSubsystem subsystem, Supplier<Double> forwardSpeed) {
m_driveSubsystem = subsystem;
// Store the supplier
m_forwardSpeed = forwardSpeed;
addRequirements(subsystem);
}
@Override
public void execute() {
// Get the value of the lambda expression, and pass it to setMotorSpeed
m_driveSubsystem.setMotorSpeed(m_forwardSpeed.get());
}
}
The command constructor accepts a variable with the type Supplier<Double>
, with Double
being the type, and the code calls the get
method on the variable to get the joystick state, passing the joystick state to a method to set the speed of a motor.