Local Variables

Local variables, as opposed to class/object fields, are defined only for the life of a method. If a method has any parameters, those parameters are available to the method body as local variables, with names that match the declared method parameter names.

For object methods, as opposed to static methods, there is also an implicit local variable named “this”, that is a reference to the object that the method is being executed on.

Bindings

JFuncMachine allows you to define additional variables using a Binding class. A binding is a list of variable names and expressions, where each expression is evaluated that it value assigned to a local variable with the corresponding name. The binding also has an expression that is executed in the context of all the bound variables.

Here is an example Binding that binds two variables, x and y, each assigned a constant int value, then the binding expression fetches the values and adds them together:

new org.jfuncmachine.compiler.model.expr.Binding(
        new Binding.BindingPair[] {
                new Binding.BindingPair("x", new IntConstant(20)),
                new Binding.BindingPair("y", new IntConstant(22))
        },
        Binding.Visibility.Separate,
        new InlineCall(Inlines.IntAdd,
                new Expression[] {
                        new GetValue("x", SimpleTypes.INT),
                        new GetValue("y", SimpleTypes.INT)
                }))

The Binding has a visibility parameter, which in the previous example is Binding.Visibility.Separate. The Separate parameter means that each binding definition does not see any of the other bindings in this binding. That is, the expression for y in the previous example could not reference the variable x that was defined just before it, although if there was already a variable x visible to the binding, it would be able to access that x.

The other option visibility setting is Previous, which means that a binding pair can see the variables that came before it in the current binding, but not those that come after it. Here is a similar example where the expression for y uses the value bound to x:

new Binding(
        new Binding.BindingPair[] {
                new Binding.BindingPair("x", new IntConstant(20)),
                new Binding.BindingPair("y",
                        new InlineCall(Inlines.IntAdd,
                                new Expression[] {
                                    new GetValue("x", SimpleTypes.INT),
                                    new IntConstant(2)
                                }))
        },
        Binding.Visibility.Previous,
        new InlineCall(Inlines.IntAdd,
                new Expression[] {
                        new GetValue("x", SimpleTypes.INT),
                        new GetValue("y", SimpleTypes.INT)
                })));

If the visibility is set to Previous then there is an error that the x variable cannot be found.

Variables defined in a binding are not visible outside the binding. If a variable in a binding has the same name as a variable that was already visible to the binding, the new variable “shadows” the existing one and the existing one cannot be accessed from within the binding.

Getting Variable Values

As you have seen in the previous two examples, the GetValue expression is used to fetch the value of a local variable. You simply supply a variable name and type to fetch the value.

Setting Variable Values

While it isn’t quite the functional way to do things, JFuncMachine allows you to set local variable using the SetValue expression, which takes a variable name and an expression to store in that variable.

The following example binds a value to a variable, then uses SetValue to update the binding with a new value, and then uses GetValue to return the value. This example also uses the Block class which allows you to define an expression as a sequence of expressions, where the Block return value is the value of the last expression.

new Binding(
        new Binding.BindingPair[] {
            new Binding.BindingPair("x", new IntConstant(20))
        },
        Binding.Visibility.Separate,
        new Block(new Expression[] {
                new SetValue("x",
                        new InlineCall(Inlines.IntAdd, new Expression[]{
                                new GetValue("x", SimpleTypes.INT),
                                new IntConstant(22)
                        })),
                new GetValue("x", SimpleTypes.INT)
        })));

Recursion with Named Bindings

Recursion is very common in functional languages to do things that would be done with loops in an imperative language. In Java, recursive function calls have a limit at how deep they can go because the stack size is limited.

JFuncMachine offers several ways to write code recursively without having to do recursive function calls. One of those is a named Binding combined with a BindingRecurse expression.

The factorial function is a common example of a recursive function. A recursive function call version of factorial in Java might look like this:

public int factorial(int n) {
    if (n < 3) {
        return 1;
    } else {
        return n * factorial(n-1);
    }
}

This factorial function is simple to understand, but it is structured in a way that really needs stack-based recursion, because the function has to hold on to the n value, invoke factorial(n-1) and wait for the response before multiplying those values together.

If you were to implement this as a while loop in Java, you’d likely have an accumulator variable and do something like this:

public int factorial(int n) {
    int acc = 1;
    while (n > 1) {
        acc = acc * n;
        n = n - 1;
    }
    return acc;
}

The named Binding + BindingRecurse version of factorial looks very similar to the while-loop version:

new Binding("func", new Binding.BindingPair[] {
        new Binding.BindingPair("n", new GetValue("n", SimpleTypes.LONG)),
        new Binding.BindingPair("acc", new LongConstant(1l))
}, Binding.Visibility.Separate,
        new If(new BinaryComparison(Tests.LT, new GetValue("n", SimpleTypes.LONG),
                new LongConstant(2l)),
                new GetValue("acc", SimpleTypes.LONG),
                new BindingRecurse("func",
                        new Expression[] {
                                new InlineCall(Inlines.LongSub, new Expression[] {
                                        new GetValue("n", SimpleTypes.LONG),
                                        new LongConstant(1l),
                                }),
                                new InlineCall(Inlines.LongMul, new Expression[] {
                                        new GetValue("n", SimpleTypes.LONG),
                                        new GetValue("acc", SimpleTypes.LONG)
                                })
                        })))

In this case, the first parameter to the Binding constructor is a name. The n and acc variables are initially bound to expressions. Then, in the body of the Binding the BindingRecurse expression re-runs the binding expression while updating the bindings. That is, the expressions in the BindingRecurse expression correspond to the values bound in the Binding, and it updates those bindings with the new expression values before executing the binding expression again.

Notice also that the BindingRecurse expression also includes the name of the Binding to recurse to, so that if you had several nested named bindings, you could choose how far back to jump.