PROPOSAL: Templated Construction Expressions (i.e., Expressions Embedded in Strings)
Schulz, Stefan
schulz at e-Spirit.de
Mon Mar 30 23:20:59 PDT 2009
I sent a proposal on embedded expressions to this list before, and it seemed to have been dismissed. I found the newly posted proposal even more complex and difficult to read, so it makes me wonder about the reasoning behind it. (Although, I am still in favor of Java supporting embedded expressions). And I agree with Per in that such a solution should support multi-line Strings as well.
Especially, as Joe did not consider embedded expressions for Coin, I dropped on writing a combined proposal on these issues and remain confused.
Stefan
> -----Original Message-----
> From: coin-dev-bounces at openjdk.java.net
> [mailto:coin-dev-bounces at openjdk.java.net] On Behalf Of John Rose
> Sent: Tuesday, March 31, 2009 2:40 AM
> To: coin-dev
> Subject: PROPOSAL: Templated Construction Expressions
> (i.e.,Expressions Embedded in Strings)
>
> On Mar 20, 2009, at 1:50 PM, John Rose wrote:
>
> > I wrote the spec. draft and implementation (in antlr) for Groovy
> > gstring syntax; I did the work with the intention of helping the JSR
> > 241 Groovy standard. It could work in Java with
> adjustments, and the
> > Groovy spec. is detailed enough to be a starting point. I don't
> > really have time to work on it though. That's why I haven't done a
> > proposal.
> >
> > For Java, to extend the string syntax and emphasize that a
> new string
> > is being constructed, I recommend this:
> >
> > new "$foo, ${bar}s."
>
> I wrote up something more specific, for the sake of this go-around.
> It is generic and pluggable enough to provide some help with XML
> templating, and SQL construction.
>
> Enjoy!
>
> http://wikis.sun.com/display/mlvm/TemplatedConstructorExpressions
>
> (Although this document is hosted on mlvm at present, it has nothing
> to do with JSR 292.)
>
> -- John
>
> P.S. For the archive, here is the original wiki source.
>
> h3. AUTHOR(S):
>
> John Rose
>
> h3. OVERVIEW
>
> String templating syntaxes are found in shell-like languages. They
> allow a flexible and natural-looking mixture of constant templates
> with non-constant interpolation. Adapt such a notation to
> Java, in a
> way that provides natural-looking templating for unformatted and
> formatted text, XML, SQL, and other applications involving foreign
> notations andstructured text.
>
> h3. FEATURE SUMMARY:
>
> h4. *1.* simple templated strings
>
> The {{new}} keyword is currently used for creating objects and
> arrays. This specification introduces another syntax based on the
> {{new}} keyword, called the *templated construction expression*:
>
> {noformat}
> int zip = 95120, phone = 5551212;
> String s = new "zip=$(zip), phone=$(phone).";
> String s2 = "zip=" + zip + ", phone=" + phone + "."; // same code
> {noformat}
>
> As with other languages, each unescaped dollar sign {{$}}
> introduces an *interpolation*, which is an arbitrary Java expression
> that contributes to the template. Everything else between
> the string
> quotes is treated as constant text; each non-empty span of string
> characters is called a *string segment*. The string segments also
> contribute to the template. As with the current plus {{+}}
> notation, each interpolation or string segment causes another
> item to
> be appended.
>
> Every interpolation ends with zero or more expressions, called the
> *interpolation arguments*. If there is exactly one interpolation
> argument, we speak unambiguously of the *interpolation expression*.
> (There are multi-argument examples below.)
>
> Such a syntax would be a merely marginal improvement over the
> current
> plus {{+}} notation for {{StringBuilder it includes two
> additional
> degree of freedom. They allow the programmer to specify templating
> mechanisms other than {{StringBuilder}}, and to more easily control
> the details of formatting for the interpolated items.
>
> h4. *2.* programmer-defined templating
>
> A templated construction expression may be qualified:
>
> {noformat}
> int zip = 95120, phone = 5551212;
> StringBuilder buf = new StringBuilder();
> buf.new "zip=$(zip), phone=$(phone).";
> String s = buf.toString(); // same result as previous example
> {noformat}
>
> In fact, if a templated construction expression is
> unqualified, it is
> exactly as if the compiler had supplied a default qualifier of {{new
> StringBuilder()}} and appended a call to {{toString}} at the end, to
> extract the resulting string.
>
> But, the programmer may provide a different object reference
> {{x}} as
> a qualifier to a templated construction expression; an object used
> this way is called a *template factory*. A qualified templated
> construction expression is equivalent to a chain of
> {{append}} method
> calls applied to the template factory, as detailed below.
>
> This allows new classes to be created which can define library-
> specific semantics for templated construction. The only requirement
> on template factories is that they supply the {{append}}
> calls implied
> by the interpolations within the templates. These {{append}} calls
> may be overloaded, and may take multiple arguments, or no
> arguments at
> all.
>
> {noformat}
> java.lang.Appendable app = ...;
> app.new "subseq: $(str, beg, end)"; // append(str, beg, end)
> {noformat}
>
> h4. *3.* generic format specifiers
>
> The dollar sign of an interpolation may be immediately followed by a
> *format specifier*, a sequence of string characters enclosed
> in angle
> brackets. These characters are collected into separate (presumably
> short) string literal which is passed as an additional leading
> argument to the method call for the interpolation; the method
> is named
> {{format}} instead of append, and may (again) take any number of
> arguments. Format specifiers may not contain unescaped right angle
> brackets; otherwise they are arbitrary, and interpreted only by the
> {{append}} call they are passed to.
>
> {noformat}
> String s = new Formatter().new "zip=$<%05d>(zip), phone=$<
> %d>(phone).".toString();
> {noformat}
>
> h4. *4.* abbreviated interpolation expressions
>
> For certain simple interpolation expressions, the enclosing
> parentheses are optional. The expressions which can drop
> parentheses
> are a decimal numeral, a name (qualified or simple), a name followed
> by one parenthesized argument list, and a name followed by one
> bracketed array index. The name must not contain any dollar
> signs in
> its spelling.
>
> {noformat}
> int zip = 95120, phone = 5551212;
> String s = new "zip=$zip, phone=$phone."; // same code
> {noformat}
>
> As always, any ambiguity between the interpolation expression and a
> following interpolation or string segment can always be resolved by
> using explicit parentheses.
>
> (Note: This last feature of abbreviation is troublesome to
> specify and
> implement, but it appears to be a worthwhile creature comfort.)
>
> h3. MAJOR ADVANTAGE:
>
> The features specified here allow programmers a superior
> notation for
> creating templated textual items. Such notations are popular
> and well
> proven in other languages, including the shells, PHP, Perl, and
> Groovy. It will reduce pressure on programmers to move to
> those other
> languages.
>
> h3. MAJOR BENEFIT:
>
> Concise, natural templated expressions are easier to code and
> maintain
> than equivalent nests of method calls.
>
> h3. MAJOR DISADVANTAGE:
>
> The JLS gets more complicated.
>
> h3. ALTERNATIVES:
>
> Programmers may use explicitly coded nests method calls; they are of
> course more verbose.
>
> h3. EXAMPLES, BEFORE/AFTER:
>
> See above and below (in the specification) for one-line examples
> demonstrating each aspect of this specification.
>
> h4. SIMPLE EXAMPLE:
>
> {noformat}
> String whom = "world";
> System.out.printlin(new "Hello, $whom!");
> {noformat}
>
> h4. ADVANCED EXAMPLE:
>
> This syntax can easily support two-phase template creation, where a
> template is first compiled and checked, and then later
> applied one or
> more times.
>
> Let's suppose a hypothetical XML snippet compiler designed for
> templated construction expressions. It might be used this way to
> compile a snippet generator with optionally typed free variables
> mapped to an API featuring a {{make}} method with positional
> arguments:
>
> {noformat}
> XMLSnippetCompiler xmlc = ...;
> xmlc.new "<rule priority='$(3, int.class)'><pattern>$1</
> pattern><action>$2</action></rule>";
> XMLSnippet xmls = xmlc.compile();
> System.out.println(xmls.make("raining", "walk inside", 5 /*medium
> pri*/));
> System.out.println(xmls.make("fire", "run outside", 1
> /*highest pri*/));
> {noformat}
>
> h3. DETAILS
>
> The sequence of string segments and interpolations of a templated
> construction expression is called its body. Each string segment
> begins with either the opening quote of the body, or the end of a
> previous
>
> The templated construction expression is broken into zero or more
> interpolations and zero or more (non-empty) string segments. These
> are presented in order to the template factory object, as
> method calls
> to {{appendText}}, {{append}}, or {{format}}.
>
> {noformat}
> x.new "a"; // sugar for x.appendText("a")
> x.new "$(y)"; // sugar for x.append(y)
> x.new "$<q>(y)"; // sugar for x.format("q",y)
> x.new "$<q>(y)"; // sugar for x.format("q",y)
> x.new "a$(y)b"; // sugar for
> x.appendText("a").append(y).appendText("b")
> x.new "a$<q>(y)b"; // sugar for
> x.appendText("a").format("q",y).appendText("b")
> x.new "a$(y)$<q>(z)"; // sugar for
> x.appendText("a").append(y).format("q",z)
> x.new ""; // degenerate sugar for x
> {noformat}
>
> There is no particular restriction on the syntax of interpolation
> argument expressions. In particular, they can contain quoted
> strings
> and templated construction expressions.
>
> {noformat}
> new "Hello, $("world").";
> new "Hello, $(new "wor$("")ld").";
> {noformat}
>
> There is no particular restriction on the type or number of
> interpolation argument expressions. Since they are sugar for
> {{append}} or {{format}} method calls, they are simply required to
> participate successfully in the rules for method call resolution.
>
> {noformat}
> x.new "$()"; // sugar for x.append()
> x.new "$(y)"; // sugar for x.append(y)
> x.new "$(y,z)"; // sugar for x.append(y,z)
> x.new "$<q>()"; // sugar for x.format("q")
> x.new "$<q>(y)"; // sugar for x.format("q",y)
> x.new "$<q>(y,z)"; // sugar for x.format("q",z)
> {noformat}
>
> If the templated construction expression is unqualified, it is
> provided with a new {{StringBuilder}} factory object, and the
> expression as a whole is closed with a {{toString}} call.
>
> For the sake of template factories which need to make the
> distinction,
> string segments are appended by {{appendText}} method call, if one
> exists on the factory object's static type; an error is
> reported if it
> is not applicable to a single {{String}}. Otherwise {{append}} is
> applied to the constant string segment, which will be a
> string literal.
>
> If the format specifier is completely empty, the leading argument to
> format is omitted, and it is up to the programmer to specify it
> explicitly in the interpolation arguments:
>
> {noformat}
> String fmt = (zip <= 99999) ? "%05d" : "%d";
> String s = new Formatter().new "zip=$<>(fmt, zip), phone=$<
> %d>(phone).".toString();
> //new Formatter().appendText
> {noformat}
>
> Here are examples of abbreviated interpolation expressions:
>
> {noformat}
> "$x" // same as "$(x)"
> "$1" // same as "$(1)"
> "$x.y" // same as "$(x.y)"
> "$x.y.z" // same as "$(x.y.z)"
> "$f(x)" // same as "$(f(x))"
> "$x.f(y)" // same as "$(x.f(y))"
> "$x[y]" // same as "$(x[y])"
> "$x.y[z]" // same as "$(x.y[z])"
> {noformat}
>
> Here are examples of abbreviated interpolation expression with
> interesting right contexts:
>
> {noformat}
> "$x." // same as "$(x)."
> "$1." // same as "$(1)."
> "$1.0" // same as "$(1).0"
> "$x.y." // same as "$(x.y)."
> "$f(x)[" // same as "$(f(x))["
> "$x[y](" // same as "$(x[y])("
> {noformat}
>
> Here are examples of illegal attempts at abbreviation:
> {noformat}
> "$$" // not same as "$($)"; must be rejected
> "$$x" // not same as "$($x)"; must be rejected
> "$x.$" // not same as "$(x.$)"; must be rejected
> "$x["... // same as "$(x["..., a likely syntax error
> "$[x]" // reserved; must be rejected
> "${x}" // reserved; must be rejected
> "$x{y}" // reserved; must be rejected
> "$x<y>" // reserved; must be rejected
> {noformat}
>
> Within a string segment of a templated construction expression, the
> dollar character may be escaped with a backslash, to prevent it from
> introducing an interpolation. Within a format specifier of an
> interpolation, the close-angle-bracket may be escaped with a
> backslash, to prevent it from terminating the format specifier. An
> unescaped dollar sign must introduce a well-formed interpolation.
>
> {noformat}
> new "\$$x.priceInDollars()"
> new "$<<\>>("has strange format of \"<>\"")."
> new "$" // must be rejected; should be new "\$"
> {noformat}
>
> h3. SPECIFICATION:
>
> The specification is complete in the running text of this document.
> It will be distilled shortly.
>
> h3. COMPILATION:
>
> As this is syntactic sugar, no new mechanisms are needed.
> The hack of
> changing {{appendText}} to {{append}} when the former is missing
> requires an extra symbol table lookup.
>
> h3. TESTING:
>
> Testing will be done the usual way, via unit tests, and by early
> access customers experimenting with the new facilities.
>
> h3. LIBRARY SUPPORT:
>
> There should be some retrofitting of libraries that perform append-
> like operations. (This is similar retrofitting to that done when
> varargs was introduced.)
>
> Suitable methods for {{appendText}} are added to {{StringBuilder}},
> {{StringBuffer}}, and {{Formatter}}.
>
> The class {{StringBuilder}}, which is privileged as the default
> template factory type, is augmented with one or more {{format}}
> methods that redirect to {{Formatter}}.
>
> {noformat}
> String s = new "zip=$<%05d>zip, phone=$phone.".toString();
> {noformat}
>
> The class {{PrintStream}}, which already has {{format}} methods, is
> also given {{appendText}} and {{append}} methods, as synonyms for
> {{print}}.
>
> {noformat}
> System.out.new "zip=$<%05d>zip, phone=$phone.".toString();
> {noformat}
>
> (*QUESTION:* What other classes could benefit from retrofitting?)
>
> h3. REFLECTIVE APIS:
>
> No changes.
>
> h3. OTHER CHANGES:
>
> None.
>
> h3. MIGRATION:
>
> The feature is for new code only.
>
> h3. COMPATIBILITY
>
> h4. BREAKING CHANGES:
>
> None. All changes are associated with previously unused syntaxes.
>
> h4. EXISTING PROGRAMS:
>
> No special interaction.
>
> h3. REFERENCES
>
> h4. EXISTING BUGS:
>
> None known.
>
> h4. URL FOR PROTOTYPE:
>
> None yet.
>
>
>
>
More information about the coin-dev
mailing list