2.0 RC1

The first public release of FreeMarker 2.0 was on 18 March 2002. Here is a summary of the changes in the Lazarus release, with respect to the last stable release of FreeMarker Classic.

NOTA BENE:

Despite the changes delineated above, the Lazarus release is almost entirely backward-compatible with FreeMarker Classic. We believe that most existing code and templates that work under FreeMarker Classic will continue working under Lazarus, with at most minimal changes. In practice, the most common cases where legacy template code is broken will be where assumptions were made about numbers and strings being equivalent. Note that in FreeMarker 2, 2 + 2 does not result in "22". The String "1" and the number 1 are entirely different animals and thus, any code will be broken if it relies on the boolean expression ("1"==1) being true. There is a "classic compatibility mode" that can be set via: Template.setClassCompatibility() that can be set so that Lazarus emulates some of the quirky behavior of FreeMarker Classic. However, any code that relied on the above "features" of FreeMarker classic really should be reworked. You are less likely to run into the other incompatibilities that are listed above. If you come across any other anomalies, please do tell us about them.

Support for Numerical operations, both arithmetic and boolean, as well as numerical ranges.

  • Scalars can now be either strings or numbers. (In FreeMarker Classic all scalars were strings.) The basic operations allowed are addition, subtraction, multiplication, division, and modulus using the +, -, *, /, and % operators respectively. Arbitrary-precision arithmetic with integers and floating point numbers are provided. Though our goal is definitely to follow the principle of least surprise, for backward compatibility, the + operator still is used for string concatenation. If either the left hand side or the right hand side of lhs + rhs is non-numerical, we revert to interpreting this as string concatenation. Thus, in FreeMarker 2, 2+2 evaluates to the number 4, while any of "2"+2 or 2+"2" or "2"+"2" evaluate to the string "22". In FreeMarker Classic, rather embarrassingly, all of the above, including 2+2, evaluated to the string "22". An attempt to use any other arithmetic operator besides the + with non-numerical operands will cause an exception to be thrown.

  • Output of a numerical expression can be made explicit via the alternative #{....} syntax. If the expression within the curly parentheses does not evaluate to a numerical value, an exception is thrown. The older ${....} syntax can evaluate to either a number or a string. In general, if, for logical reasons, the output must be numerical, it is preferable to use the #{...} syntax, since it adds an extra sanity check. Note that if, by some miracle, the character sequence "#{" occurs in your template, you will have to use a workaround to prevent problems. (The <noparse> directive is one possibility.)

  • In this release, there is a facility for specifying the number of digits to show after the decimal point. The following code specifies to show at least 3 digits after the decimal point but not more than 6. This is optional. This option is only available if you use the #{...} syntax.

    #{foo + bar ; m3M6}  

    (Note that the above is something of a stopgap measure. Future releases will move toward supporting fully internationalization and localization of number and currency formatting.

  • Numerical expressions can be used in boolean expressions via the comparison operators: lt, gt, lte, and gte. In the web space, where FreeMarker is most used in practice, using the more natural operators such as < and > would tend to confuse HTML-oriented editors. An attempt to compare non-numerical expressions using these operators leads to a TemplateException being thrown. If, by some coincidence, you have variables named "lt", "gt", "lte", or "gte", you will have to change their names, since they are now keywords in the language.

  • Numerical ranges are supported.

    <#list 1990..2001 as year>
      blah blah in the year ${year} blah
    </#list> 

    The left hand and right hand sides of the .. operator must be numerical, or an exception is thrown. They also need not be literal numbers, but can be more complex expressions that evaluate to a numerical scalar value. Note that it is also possible to write a range that descends in value:

    <#list 2001..1990 as year>
      blah blah in the year ${year} blah blah
    </#list>  

API Changes

  • The TemplateNumberModel interface and the SimpleNumber implementation were added to support exposing numerical values.

  • The TemplateListModel API in FreeMarker Classic had some design problems -- particularly in terms of supporting thread-safe code. It has been deprecated in favor of the following API's: TemplateCollectionModel and TemplateSequenceModel. The SimpleList class was refactored to implement the above interfaces (and paradoxically, does not implement the TemplateListModel interface.) Code that uses the deprecated TemplateListModel should be refactored.

  • The Expose Package by Attila Szegedi has been made an integral part of the FreeMarker distribution and is now under the freemarker.ext.* hierarchy. This package provides advanced models for representing arbitrary Java objects as template models, for representing XML documents as template models, as well as classes to facilitate the integration of FreeMarker with servlets and Ant.

  • In FreeMarker Classic, there were some utility classes such as freemarker.template.utility.Addition etcetera that existed as workarounds for the lack of numerical operations in FreeMarker. Those have been removed and will probably not be missed.

  • In FreeMarker Classic, the SimpleScalar object was mutable, it had a setValue method. This was fairly obviously a design mistake. Any code that relied on this must be refactored. Note that in this release, both SimpleScalar and the newly introduced SimpleNumber are both immutable and final.

Syntactical Miscellany

  • The if-elseif-else syntax was introduced. FreeMarker classic only had if-else. This construct should probably (in the opinion of the author of this document -- Revusky) be used in preference to switch-case since the switch-case with fall-through is a notoriously error-prone construct for most mortal men.

  • You can now do a multiple assignment in one <assign...> directive. For example: <assign x = 1, y = price*items, message="foo">

  • A scalar will no longer be interpreted as a one-item list in a <list...> or <#foreach...> block. If you have code that relied on this feature, there is an easy workaround, since you can simply define a list literal with exactly one item.

     <assign y=[x]>
     and then...
     <list y as item>...</list>