For our early templated string prototypes, we restricted embedded expressions 
to just basic accessors and basic arithmetic. The intent was to keep things 
easy to read and to prevent side effects. Over time, we began thinking this 
restriction was unduly harsh. More precisely, we worried it that it would 
result in a complex, difficult-to-defend boundary. But we still would like 
users to not rely on side-effects.

Consequently, a new proposal for embedded expressions - we would allow any Java 
expression with the restriction that you can't use single quotes, double quotes 
or escape sequences. We opted to keep this restriction to allow tools (ex., 
syntax highlighters) to isolate embedded expressions within strings without 
requiring sophisticated parsing.

Given that an unprocessed templated string involves at least some deferred 
evaluation, should we frame templated string parameters as being more like 
method parameters (all parameters evaluated eagerly, left to right), or should 
we treat them as lambda expressions, which may capture (effectively final) 
variables from the environment, and evaluate the full parameters expressions 
when they are needed?

Note too that the effectively final restriction rules out some of the worst 
side-effect offenders, like:

    int x = 0;
    formatter."One \{x++} plus two \{x++} is three \{x}";

-- even if we intend to then do eager evaluation!

To help understand the issue, let's look at a simplification of how the two 
different paradigms (method parameter vs. lambda) might be implemented. Example:

    int x = 0;

    int method1() {
        System.out.println("one");
        return 1;
    }

    int method2() {
        System.out.println("two");
        return 2;
    }

    System.out.println("Before TemplatedString");
    TemplatedString ts = "\{x} and \{method1()} and \{method2()}";
    System.out.println("After TemplatedString");
    System.out.println(CONCAT.apply(ts));
    System.out.println("After Policy");

The method parameter paradigm would generate something like following for 
TemplatedString ts = "\{x} and \{method1()} and \{method2()}"; statement. 
Basically, capture the values of the evaluated expressions in instance fields.

    TemplatedString ts = new TemplatedString() {
        int expr$0 = x;
        int expr$1 = method1();
        int expr$2 = method2();

        String template() {
            return "\uFFFC and \uFFFC and \uFFFC";
        }

        List<Object> values() {
            return List.of(expr$0, expr$1, expr$2);
        }

        String concat() {
            return expr$0 + " and " + expr$1 + " and " + expr$2;
        }

        List<MethodHandle> vars() {
            return List.of(lookupGetter("expr$0"), lookupGetter("expr$1"), 
lookupGetter("expr$2"));
        }
    }

The lambda paradigm would generate something like following. Basically, wrap 
the expression in an instance method and capturing effectively final values 
used by the methods in instance fields (ala lambda.)

    TemplatedString ts = new TemplatedString() {
int var$x = x;

        int expr$0() {
            return var$x;
        }

        int expr$1() {
            return method1();
        }

        int expr$2() {
            return method2();
        }

        String template() {
            return "\uFFFC and \uFFFC and \uFFFC";
        }

        List<Object> values() {
            return List.of(expr$0(), expr$1(), expr$2());
        }

        String concat() {
            return expr$0() + " and " + expr$1() + " and " + expr$2();
        }

        List<MethodHandle> vars() {
            return List.of(lookupMethod("expr$0"), lookupMethod("expr$1"), 
lookupMethod("expr$2"));
        }
    }

The output from the method parameter paradigm would be:

    Before TemplatedString
    one
    two
    After TemplatedString
    0 and 1 and 2
    After Policy

>From the lambda paradigm would be:

    Before TemplatedString
    After TemplatedString
    one
    two
    0 and 1 and 2
    After Policy

To help us evaluating the tradeoffs between the two paradigms, our question to 
the experts is, "What are the ramifications of each?" Please resist the 
temptation to express a preference for one or the other.

Thank you.

Cheers,

-- Jim

Reply via email to