FreeMarker issues (was FreeMarker XML issues)

15 messages Options
Embed this post
Permalink
Yuh-Ruey Chen

FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
On Fri, Sep 11, 2009 at 12:37 AM, Daniel Dekany <[hidden email]> wrote:
Friday, September 11, 2009, 4:10:28 AM, YR Chen wrote:

> Hmm, I'll give that a try. I did implement a couple extra things
> like wrapping an Enum class into a Hash. Since I believe Enums are a
> Java 5 feature, it might not be possible to add the FreeMarker code base.

Enum support in FreeMarker:
http://freemarker.org/docs/pgui_misc_beanwrapper.html#jdk_15_enums

--
Best regards,
 Daniel Dekany


Okay, I've got my ObjectWrapper to extend from BeansWrapper, and added some better (IMO) enum handling:

    /**
     * Add special handling for class objects.
     */
    @Override
    protected ModelFactory getModelFactory(@SuppressWarnings("unchecked") Class clazz) {
        if (clazz.equals(Class.class)) {
            return CLASS_MODEL_FACTORY;
        }
        return super.getModelFactory(clazz);
    }
   
    /**
     * Uses BeansWrapper.getEnumModels() for Enum classes, and StringModel for other
     * classes.
     */
    protected static final ModelFactory CLASS_MODEL_FACTORY = new ModelFactory() {
        public TemplateModel create(Object object,
                freemarker.template.ObjectWrapper wrapper) {
            BeansWrapper beansWrapper = (BeansWrapper) wrapper;
            Class<?> clazz = (Class<?>) object;
            // If class is Enum, use beansWrapper.getEnumModels().
            if (clazz.isEnum()) {
                try {
                    return beansWrapper.getEnumModels().get(clazz.getName());
                } catch (TemplateModelException e) {
                    // This should never occur, since a TemplateModelException is only
                    // thrown when the enum class cannot be found, but the enum class
                    // obviously exists here.
                    throw new IllegalStateException(e);
                }
            }
            // Otherwise, use the default StringModel.
            return new StringModel(object, beansWrapper);
        }
    };

I believe this code could work for Java 1.2+ if the generics and annotations are stripped out and the isEnum() is reflectively called.


I did find another issue with BeansWrapper though: the seq_contains builtin doesn't work correctly for Sets. The seq_contains builtin first checks if the object is a TemplateSequenceModel and then uses indexing operations (get(int)), before checking if the object is a TemplateCollectionModel. Since Sets are wrapped in a CollectionModel, which implements both TemplateSequenceModel and TemplateCollectionModel, it's treated as a TemplateSequenceModel in seq_containsBI, and get(int) throws an exception for Sets.

I have a very ugly and hacky fix for that. I created a class in pkg freemarker.core so it can access BuiltIn.builtins, which is used to replace the seq_contains builtin with the fixed version. The fixed version is basically a copy of the seq_containsBI with the TemplateSequenceModel and TemplateCollectionModel checking reversed.

I suppose that's a testament to the need for an API revamp for builtins.

By the way, I would have reported this bug to the SourceForge bug tracker, but it hardly looks used (practically no discussion on it, and plenty of spam).

Regards, Yuh-Ruey Chen

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Daniel Dekany

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Sunday, September 13, 2009, 4:52:59 AM, YR Chen wrote:

> On Fri, Sep 11, 2009 at 12:37 AM, Daniel Dekany <[hidden email]> wrote:
> Friday, September 11, 2009, 4:10:28 AM, YR Chen wrote:
>
>> Hmm, I'll give that a try. I did implement a couple extra things
>> like wrapping an Enum class into a Hash. Since I believe Enums are a
>> Java 5 feature, it might not be possible to add the FreeMarker code base.
>
> Enum support in FreeMarker:
> http://freemarker.org/docs/pgui_misc_beanwrapper.html#jdk_15_enums
>
> --
> Best regards,
>  Daniel Dekany
>
>
> Okay, I've got my ObjectWrapper to extend from BeansWrapper, and
> added some better (IMO) enum handling:
>
>     /**
>      * Add special handling for class objects.
>      */
>     @Override
>     protected ModelFactory
> getModelFactory(@SuppressWarnings("unchecked") Class clazz) {
>         if (clazz.equals(Class.class)) {
>             return CLASS_MODEL_FACTORY;
>         }
>         return super.getModelFactory(clazz);
>     }
>    
>     /**
>      * Uses BeansWrapper.getEnumModels() for Enum classes, and StringModel for other
>      * classes.
>      */
>     protected static final ModelFactory CLASS_MODEL_FACTORY = new ModelFactory() {
>         public TemplateModel create(Object object,
>                 freemarker.template.ObjectWrapper wrapper) {
>             BeansWrapper beansWrapper = (BeansWrapper) wrapper;
>             Class<?> clazz = (Class<?>) object;
>             // If class is Enum, use beansWrapper.getEnumModels().
>             if (clazz.isEnum()) {
>                 try {
>                     return
> beansWrapper.getEnumModels().get(clazz.getName());
>                 } catch (TemplateModelException e) {
>                     // This should never occur, since a TemplateModelException is only
>                     // thrown when the enum class cannot be found, but the enum class
>                     // obviously exists here.
>                     throw new IllegalStateException(e);
>                 }
>             }
>             // Otherwise, use the default StringModel.
>             return new StringModel(object, beansWrapper);
>         }
>     };
>
> I believe this code could work for Java 1.2+ if the generics and
> annotations are stripped out and the isEnum() is reflectively called.

(I left this part to Attila...)

> I did find another issue with BeansWrapper though: the seq_contains
> builtin doesn't work correctly for Sets. The seq_contains builtin
> first checks if the object is a TemplateSequenceModel and then uses
> indexing operations (get(int)), before checking if the object is a
> TemplateCollectionModel. Since Sets are wrapped in a
> CollectionModel, which implements both TemplateSequenceModel and
> TemplateCollectionModel, it's treated as a TemplateSequenceModel in
> seq_containsBI, and get(int) throws an exception for Sets.
>
> I have a very ugly and hacky fix for that. I created a class in pkg
> freemarker.core so it can access BuiltIn.builtins, which is used to
> replace the seq_contains builtin with the fixed version. The fixed
> version is basically a copy of the seq_containsBI with the
> TemplateSequenceModel and TemplateCollectionModel checking reversed.

Unless someone will tell it's not backward-compatible, that fix will
be in the next release.

> I suppose that's a testament to the need for an API revamp for builtins.

I'm not 100% sure what you mean, but it's deliberate that you can't
add built-ins. I you could, we couldn't add new ones in a
backward-compatible way. That's why they are syntactically separated
from plain method calls. Overriding built-ins is also not fun, because
they are part of the template language, quite much like operators are,
and they are documented in the official manual, so it would be really
confusing if some user customize them.

> By the way, I would have reported this bug to the SourceForge bug
> tracker,

And you should have.

> but it hardly looks used (practically no discussion on it,

I don't know what kind of projects you worked in, but I think the
activity there is quite much usual among OS project. But, maybe you
only listed the entries with "open" status?

> and plenty of spam).

Plenty? Where? I have found (and deleted) two.

> Regards, Yuh-Ruey Chen
--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Yuh-Ruey Chen

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Daniel Dekany wrote:

> Sunday, September 13, 2009, 4:52:59 AM, YR Chen wrote:
> > I suppose that's a testament to the need for an API revamp for builtins.
>
> I'm not 100% sure what you mean, but it's deliberate that you can't
> add built-ins. I you could, we couldn't add new ones in a
> backward-compatible way. That's why they are syntactically separated
> from plain method calls. Overriding built-ins is also not fun, because
> they are part of the template language, quite much like operators are,
> and they are documented in the official manual, so it would be really
> confusing if some user customize them.
>  

Well I have to disagree with that. If there's one thing that I don't
like about the FreeMarker design - it's the builtins. Most of them
simply provide equivalent functionality with methods already in the Java
API, e.g. substring, contains, seq_contains. Whether they are "quite
much like operators are" is moot, since in Java you can override most
operators you want (in the generic sense of the term "operator", so I
mean Java methods). I can understand the desire not to have builtins
collide with the model, but that doesn't preclude them from being
user-defined. After all, FreeMarker already has namespaces.

Look at JavaScript for inspiration. It has plenty of builtins but they
can be overridden. And since it's the user that's overriding them, he
knows the exact semantics of it, so I don't see how it can be confusing
at all.

IMO, there are relatively few builtins that can be considered as core
operators: eval, type builtins (int, float, etc.), interpret, and some
others. In fact, I would have those particular builtins be actual core
language operators rather than "builtins". The rest are hardly related
to the core and should be fully customizable.

> > but it hardly looks used (practically no discussion on it,
>
> I don't know what kind of projects you worked in, but I think the
> activity there is quite much usual among OS project. But, maybe you
> only listed the entries with "open" status?
>
> > and plenty of spam).
>
> Plenty? Where? I have found (and deleted) two.
>  

Oops, I was actually listing all entries - including deleted ones. My bad :p

Regards, Yuh-Ruey

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Daniel Dekany

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Monday, September 14, 2009, 7:35:53 AM, Yuh-Ruey Chen wrote:

> Daniel Dekany wrote:
>> Sunday, September 13, 2009, 4:52:59 AM, YR Chen wrote:
>> > I suppose that's a testament to the need for an API revamp for builtins.
>>
>> I'm not 100% sure what you mean, but it's deliberate that you can't
>> add built-ins. I you could, we couldn't add new ones in a
>> backward-compatible way. That's why they are syntactically separated
>> from plain method calls. Overriding built-ins is also not fun, because
>> they are part of the template language, quite much like operators are,
>> and they are documented in the official manual, so it would be really
>> confusing if some user customize them.
>>  
>
> Well I have to disagree with that. If there's one thing that I don't
> like about the FreeMarker design - it's the builtins. Most of them
> simply provide equivalent functionality with methods already in the
> Java API, e.g. substring, contains, seq_contains.

And for some there is no equivalent... now assuming the template
author is a Java programmer who knows what is in the Java API-s and
what is not, this wouldn't be automatically a problem. Only of course
with the current language design we stuck due to the object wrapping.
Something that is exposed to be, say, a string in the template
language might not be a String on the Java-language-side. Surely we
could still simulate that it has the java.lang.String methods, but
it's not that rare that the same object had to expose the actual Java
methods of the unwrapped object, or that the object is a custom
TempateModel object implementation and hence it has methods that are
not part of java.lang.String. And so on, so on... These can cause name
clashes. So at the end you need some kind of trick to separate plain
method calls from built-in method class, and it's using "?" instead of
".".

> Whether they are "quite
> much like operators are" is moot, since in Java you can override most
> operators you want (in the generic sense of the term "operator", so I
> mean Java methods). I can understand the desire not to have builtins
> collide with the model, but that doesn't preclude them from being
> user-defined. After all, FreeMarker already has namespaces.

In my vaporware template language I actually don't have bulilt-ins
(and not even built-in directives, you know, the # things), only
methods. There is a set of so called core methods, that is part of the
template language, but you can change it if you explicitly create a
custom template language, with a new name and default extension, one
that doesn't collide with the names and extensions of the standard
template languages. (As far as you don't also customize syntax, it's
not difficult to implement, it's just that you have to design the
engine with multiple template languages in mind.) So it's not like I
will protect FM built-ins to the last blood, but I also know it's not
as a silly concept as it looks. I have suffered with this a lot, and
it's not at all free to drop them. Thing is, you don't want clashes
with the data-model (Java guys are paranoids :) ), and the data-model
variables should be available without any prefix (like "$" or "d:"),
because it's what you use the most in an MVC-ish template. So what
remains for those poor top-level core methods (and core variables,
like "locale", etc.), the equivalents of FM-s built-ins + #
directives? Because I don't think it's very acceptable to write
namespace prefixes or whatever prefixes before every single core
method call either. (I won't tell my solution right now... let's see
what idea others has.) FM actually solved this problem with "#" vs "@"
for directives, and "." VS "?" for built-ins. This is not a that bad
compromise.

> Look at JavaScript for inspiration.
> It has plenty of builtins but they can be overridden.

(I'm actually not exactly known as a JavaScript fan... or, for that
mater, neither as a big fan of the "let's make everything incredibly
dynamic, while we don't feel like developing the static languages (or
not ignoring the new ones), so we will have real reason to hate them
and to point out how the dynamic ones are more productive" movement.)

> And since it's the user that's overriding them, he knows the exact
> semantics of it, so I don't see how it can be confusing at all.

Who is "the user"? Because it's certainly not one guy, rather a few.
Even if it's one guy, certainly it will be another one a few years
later. Not to mention the tendency of people to forget things they
did, especially if they participate in several projects over the
years. So, what going to happen is that the new guy or a some who just
has forgotten things will Google things, opens the FreeMarker Manual,
see what built-ins are available and what they do, but... oops. (Then
you can continue with supporting IDE-s and other text editors when you
have a custom set of built-ins. It's possible if you expose some API-s
that help the plugin authors, but, yet another place where
customization can come back to you.)

> IMO, there are relatively few builtins that can be considered as core
> operators: eval, type builtins (int, float, etc.), interpret, and some
> others. In fact, I would have those particular builtins be actual core
> language operators rather than "builtins". The rest are hardly related
> to the core and should be fully customizable.

A design goal with a fat set of core "methods" (in FM they are the
"built-ins:, and the # directives) is that the wherever the user
writes a template, he can be sure they are there, and he can access
them immediately. He doesn't even have to suffer with importing
something like, I don't know, "fm://utils" and assign it to a prefix,
which BTW can be quite annoying if you are working with many little
independent template fragments (message templates, UI bits in a CMS,
etc.). Also he doesn't need to wonder whether, like, HTML escaping is
a core method or a utility method. But of course, splitting the
out-of-the-box methods into core and utility groups has its advantages
too. But this is about seeking compromises. I actually went back and
forth between fat-core and thin-core + utils design, but currently I
would go for fat-core. But that decision very much depends on what
tricks you find out to avoid the earlier mentioned name clashes.

>> > but it hardly looks used (practically no discussion on it,
>>
>> I don't know what kind of projects you worked in, but I think the
>> activity there is quite much usual among OS project. But, maybe you
>> only listed the entries with "open" status?
>>
>> > and plenty of spam).
>>
>> Plenty? Where? I have found (and deleted) two.
>>  
>
> Oops, I was actually listing all entries - including deleted ones. My bad :p
>
> Regards, Yuh-Ruey

--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Yuh-Ruey Chen

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Daniel Dekany wrote:

> Monday, September 14, 2009, 7:35:53 AM, Yuh-Ruey Chen wrote:
>
> > Daniel Dekany wrote:
> >> Sunday, September 13, 2009, 4:52:59 AM, YR Chen wrote:
> >> > I suppose that's a testament to the need for an API revamp for builtins.
> >>
> >> I'm not 100% sure what you mean, but it's deliberate that you can't
> >> add built-ins. I you could, we couldn't add new ones in a
> >> backward-compatible way. That's why they are syntactically separated
> >> from plain method calls. Overriding built-ins is also not fun, because
> >> they are part of the template language, quite much like operators are,
> >> and they are documented in the official manual, so it would be really
> >> confusing if some user customize them.
> >>  
> >
> > Well I have to disagree with that. If there's one thing that I don't
> > like about the FreeMarker design - it's the builtins. Most of them
> > simply provide equivalent functionality with methods already in the
> > Java API, e.g. substring, contains, seq_contains.
>
> And for some there is no equivalent... now assuming the template
> author is a Java programmer who knows what is in the Java API-s and
> what is not, this wouldn't be automatically a problem. Only of course
> with the current language design we stuck due to the object wrapping.
> Something that is exposed to be, say, a string in the template
> language might not be a String on the Java-language-side. Surely we
> could still simulate that it has the java.lang.String methods, but
> it's not that rare that the same object had to expose the actual Java
> methods of the unwrapped object, or that the object is a custom
> TempateModel object implementation and hence it has methods that are
> not part of java.lang.String. And so on, so on... These can cause name
> clashes. So at the end you need some kind of trick to separate plain
> method calls from built-in method class, and it's using "?" instead of
> ".".
>
> > Whether they are "quite
> > much like operators are" is moot, since in Java you can override most
> > operators you want (in the generic sense of the term "operator", so I
> > mean Java methods). I can understand the desire not to have builtins
> > collide with the model, but that doesn't preclude them from being
> > user-defined. After all, FreeMarker already has namespaces.
>
> In my vaporware template language I actually don't have bulilt-ins
> (and not even built-in directives, you know, the # things), only
> methods. There is a set of so called core methods, that is part of the
> template language, but you can change it if you explicitly create a
> custom template language, with a new name and default extension, one
> that doesn't collide with the names and extensions of the standard
> template languages. (As far as you don't also customize syntax, it's
> not difficult to implement, it's just that you have to design the
> engine with multiple template languages in mind.) So it's not like I
> will protect FM built-ins to the last blood, but I also know it's not
> as a silly concept as it looks. I have suffered with this a lot, and
> it's not at all free to drop them. Thing is, you don't want clashes
> with the data-model (Java guys are paranoids :) ), and the data-model
> variables should be available without any prefix (like "$" or "d:"),
> because it's what you use the most in an MVC-ish template. So what
> remains for those poor top-level core methods (and core variables,
> like "locale", etc.), the equivalents of FM-s built-ins + #
> directives? Because I don't think it's very acceptable to write
> namespace prefixes or whatever prefixes before every single core
> method call either. (I won't tell my solution right now... let's see
> what idea others has.) FM actually solved this problem with "#" vs "@"
> for directives, and "." VS "?" for built-ins. This is not a that bad
> compromise.
>  

I do like the idea of a minimal design that can be extended into custom
template languages, so I very much like to see what you have in mind :)

I'm actually not too bothered with the fact that there are builtins or
that the syntax is a bit odd-looking. But I just don't think builtins
functions should be treated specially from user-defined functions. Same
with builtin directives vs. user-defined directives (more on this
later). Builtin and user-defined functions should have a single unified
syntax. Right now, builtin functions use the suffix "?" syntax and can't
be treated as first-class objects (can't be passed around), while
user-defined functions are actually in the data model and are
first-class objects.

Adding functions to the data model (or shared vars) always feels a bit
clunky to me, because it does collide with the rest of the data model.
So user-defined functions can either collide with the data model or the
builtin functions, and I think going with the latter is a both a cleaner
and safer design. Cleaner because the semantics and syntax of all
functions are unified (hopefully leading to cleaner code as well), and
safer because the data model is much more variable then the list of
functions (e.g. if I have a function "foo", it's more likely that some
data model with a "foo" to collide with it than there would be another
user-defined function named "foo" to collide with it).

Now to unifying user-defined and builtin directives. There are other
syntactical differences besides the "#" vs. "@". Some like #assign and
#if can't be done with user-defined directives. And unless we want a
XML-like verboseness ala JSTL's choose/when, there's not a good way
around it (though I'm trying to think of a way they could be
user-defined yet not verbose).

But what about #list and some other directives that use the "as"
keyword? These directives use the "as" keyword in two ways: introducing
a new local (loop) variable (if it requires an end tag), or introducing
a variable to the template's scope (if it cannot have an end tag).
Meanwhile user-defined directives must use the odd semicolon syntax to
introduce new local variables, and cannot introduce template-scope
variables. I think there is room for unification here.

As to whether it's a good idea treat builtins and user-defined functions
and directives the same, it should at the very least be configurable -
see below (response to JavaScript).



So here's a rough template language design brainstorming session:

Directives:

Both user-defined and builtins use [#] and share the same "namespace".
User-defined directives cannot override builtins.

[#foo arg1, arg2 as var1, var2]body[/#foo]
Call directive foo with params arg1 and arg2, introducing new "loop"
vars var1 and var2 to body.

[#foo arg1, arg2 as arg3, arg4/]
Call directive foo with params arg1 and arg2, introducing new vars var1
and var2 to the parent scope. Of course, if #foo requires a body, this
should throw an exception somewhere.

[#macro foo, arg1, arg2 as var1, var2]
   stuff
   [#set var1=blah]
   [#set var2=blah]
   stuff
[/#macro]
Replaces macro foo with a directive that uses params arg1 and arg2, and
introduces vars var1 and var2. var1 and var2 have C-like "call by
reference" semantics (as opposed to Java's "call by value" semantics),
i.e. setting var1 actually sets the loop variable.

[#macro foo, arg1=dv, ...args as var1, ...vars]
   [#list args as arg]stuff[/#list]
   [#list vars as var][#set var=blah][/#list]
[/#macro]
Example showcasing variadic parameters and default parameters. "vars" is
a list of references, so that in [#list vars as var], "var" is a
reference, so [#set var=...] works as you'd expect.

Functions:

Both builtin and user-defined functions share the exact same syntax.
Whether builtins are overridable should be configurable (see below).
There are two forms that the user can use: the familiar Java prefix
style, or the FreeMarker suffix style.

To try to keep the syntax as consistent as possible, I'm using "#" for
template functions. So to the user, "#" means "template directive/function".

${#blah(x)}
Equivalent to FTL expression: ${x?blah}.

${x#blah}
Equivalent to FTL expression: ${x?blah}.

[#function blah, arg1, arg2]body[/#function]
Redefines blah function.

${#blah(arg1, arg2)}
Equivalent to FTL expression: ${arg1?blah(arg2)}

${arg1#blah(arg2)}
Equivalent to FTL expression: ${arg1?blah(arg2)}

[#function blah, arg1=dv, ...args]body[/#function]
Showcasing variadic parameters and default parameters.

The template language will have very light "bean wrappers", so there's
no need for builtins like "substring" or "contains".

> > Look at JavaScript for inspiration.
> > It has plenty of builtins but they can be overridden.
>
> (I'm actually not exactly known as a JavaScript fan... or, for that
> mater, neither as a big fan of the "let's make everything incredibly
> dynamic, while we don't feel like developing the static languages (or
> not ignoring the new ones), so we will have real reason to hate them
> and to point out how the dynamic ones are more productive" movement.)
>  

Perhaps JavaScript is a bad example. It's too simplistic to say that
something should be dynamic or not, when there are multiple ways
something can be dynamic. For builtin overriding, I can imagine several
"dynamic levels" that we can choose:

1) Allowing builtins to be overridden by anything (and even deleted ala
setting it to null) within the template
2) Allowing builtins to be overridden by a function that matches the
same interface of the builtin within the template
3) Same as (1) or (2) except template engine can be configured not to
allow builtin overriding
4) Same as (1) except builtins can only be overridden during
configuration (from Java)
5) Same as (2) except builtins can only be overridden during
configuration (from Java) and the interface semantics can be more
precise with the static type checking
6) Same as any of the above but allow only non-"core" builtins to be
overwritten, where a "core" builtin would be eval, interpret, etc.
7) Cannot be overwritten, period - not even a Java API to do so (status quo)

> > And since it's the user that's overriding them, he knows the exact
> > semantics of it, so I don't see how it can be confusing at all.
>
> Who is "the user"? Because it's certainly not one guy, rather a few.
> Even if it's one guy, certainly it will be another one a few years
> later. Not to mention the tendency of people to forget things they
> did, especially if they participate in several projects over the
> years. So, what going to happen is that the new guy or a some who just
> has forgotten things will Google things, opens the FreeMarker Manual,
> see what built-ins are available and what they do, but... oops. (Then
> you can continue with supporting IDE-s and other text editors when you
> have a custom set of built-ins. It's possible if you expose some API-s
> that help the plugin authors, but, yet another place where
> customization can come back to you.)
>  

That's a problem with code in general and hardly an argument for keeping
builtins unconfigurable. You could easily mention in the docs that
builtins can be redefined in user code (whether during configuration or
within the template).

And I don't find the IDE support argument very convincing. If builtins
are configurable in Java, then we have javadocs and method signatures
that can provide hints. If builtins can be overridden within the
template, well that's just the nature of dynamic languages, although
with very good type inferencing, editor support is somewhat possible
(there are editors out there that provide decent type/param inferencing
for certain dynamic languages).

> > IMO, there are relatively few builtins that can be considered as core
> > operators: eval, type builtins (int, float, etc.), interpret, and some
> > others. In fact, I would have those particular builtins be actual core
> > language operators rather than "builtins". The rest are hardly related
> > to the core and should be fully customizable.
>
> A design goal with a fat set of core "methods" (in FM they are the
> "built-ins:, and the # directives) is that the wherever the user
> writes a template, he can be sure they are there, and he can access
> them immediately. He doesn't even have to suffer with importing
> something like, I don't know, "fm://utils" and assign it to a prefix,
> which BTW can be quite annoying if you are working with many little
> independent template fragments (message templates, UI bits in a CMS,
> etc.). Also he doesn't need to wonder whether, like, HTML escaping is
> a core method or a utility method. But of course, splitting the
> out-of-the-box methods into core and utility groups has its advantages
> too. But this is about seeking compromises. I actually went back and
> forth between fat-core and thin-core + utils design, but currently I
> would go for fat-core. But that decision very much depends on what
> tricks you find out to avoid the earlier mentioned name clashes.
>  

I'm fine with plenty of builtins. You can have a small set of core
builtins and then libraries that provide other "builtins" that are
autoimported into the same "namespace". Then allow the user to configure
exactly what libraries are autoimported (with the default possibly being
importing everything). In fact, I'd like the "standard library" to be
much bigger.

Regards, Yuh-Ruey

------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Daniel Dekany

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Tuesday, September 15, 2009, 11:37:15 AM, Yuh-Ruey Chen wrote:

[snip]
> I do like the idea of a minimal design that can be extended into custom
> template languages, so I very much like to see what you have in mind :)
>
> I'm actually not too bothered with the fact that there are builtins or
> that the syntax is a bit odd-looking.

It's not that odd-looking... consider "?" as ".", that has something
above it. Both is a sentence-ending punctuation character.

> But I just don't think builtins functions should be treated
> specially from user-defined functions. Same with builtin directives
> vs. user-defined directives (more on this later). Builtin and
> user-defined functions should have a single unified syntax. Right
> now, builtin functions use the suffix "?" syntax and can't be
> treated as first-class objects (can't be passed around), while
> user-defined functions are actually in the data model and are
> first-class objects.

I agree with that... but note that treating the built-in
directives/functions/methods/whatever-you-call-them is not possible
for all of them, because some of them has before-runtime effects.
(Anyway, in such cases I planned to drop an exception if and when you
try to call them. So you still can get the thing as a value, and,
like, query it's name and namespace, but you can't call it.)

> Adding functions to the data model (or shared vars) always feels a bit
> clunky to me, because it does collide with the rest of the data model.

Yes. But later ?new and #import was introduced to counter that
tradition. (BTW, one of the big problems of FM is that the whole "FTL
library" thing is not very streamlined... For example, you can't just
drop a someoneelsesftllibrary.jar into the classpath of your app., and
then #import it. Things like that...)

> So user-defined functions can either collide with the data model or the
> builtin functions, and I think going with the latter is a both a cleaner
> and safer design.

*If* that's the only two possibility, I agree.

> Cleaner because the semantics and syntax of all functions are
> unified (hopefully leading to cleaner code as well), and safer
> because the data model is much more variable then the list of
> functions (e.g. if I have a function "foo", it's more likely that
> some data model with a "foo" to collide with it than there would be
> another user-defined function named "foo" to collide with it).
>
> Now to unifying user-defined and builtin directives. There are other
> syntactical differences besides the "#" vs. "@". Some like #assign and
> #if can't be done with user-defined directives. And unless we want a
> XML-like verboseness ala JSTL's choose/when, there's not a good way
> around it (though I'm trying to think of a way they could be
> user-defined yet not verbose).

Yeah, that's the other tricky part of the unification... You will have
to add some extra features to your template language, that you maybe
wouldn't add otherwise. Anyway, I found that it wasn't a big problem
in practice. Like, I wanted out-parameters feature anyway, and
something like "set target=source" can be seen as an optional
shorthand for an application of that. But I don't think it's wise to
allow the usage of that particular shorthand for user-defined stuff
(but it's really easy to allow it technically... actually, the extra
work is disallowing it). And that wasn't the point anyway... the point
is that *semantically* the "set x=1" is nothing special, it's really
just "set 1; x". Hence, the "=" thing itself is no in the way if you
want to call dynamically something that uses that.

> But what about #list and some other directives that use the "as"
> keyword?

Back then I decided to get rid of "as", "in" and such, and just use
the unified syntax (";"). Since the expression language clearly
separate the in- and out-parameters (with ";"), it's obvious which one
is the source, and which one declare the block-scope variable. Now
there is a compromise here: "list foo as bar" is more telling than
"list foo; bar". I to find something better instead of ";" but
whenever I did it always spoiled something else that I found to be a
bigger problem... so currently it's ";". So, back to the compromise, I
found it's not a that big compromise eventually, if you assume the
user will face a ";" when using some custom macros anyway. Then it's
just better that there is only one syntax he has to learn: use ";",
end of story.

The other possibility is to allow declaring the usage of "as" or "in"
in the formal parameter list of the macro definitions... only,
depending on what purpose the macro has, you may want another
keyword... which, you won't get, custom keywords. I don't think it's
need to go into it why not...

> These directives use the "as" keyword in two ways: introducing
> a new local (loop) variable (if it requires an end tag), or introducing
> a variable to the template's scope (if it cannot have an end tag).
> Meanwhile user-defined directives must use the odd semicolon syntax to
> introduce new local variables, and cannot introduce template-scope
> variables. I think there is room for unification here.
>
> As to whether it's a good idea treat builtins and user-defined functions
> and directives the same, it should at the very least be configurable -

Hardly. To unify them, you need to touch some quite fundamental rules
of the language. In FTL, directives meant to generating markup (hence
they kind of look like HTML tags), while other expressions (like
function calls) aren't. The importance of this shows when you apply
#escape; it will not escape the output of directives. Also, in
FreeMarker only directives can return the result progressively (i.e.,
they start to output it before it's complete). So, what I'm saying,
that in the case of FreeMarker there is fundamental difference between
the two. (I'm not saying there should be... as I said, in my planned
solution there isn't. But of course, that has some painful
consequences too...)

BTW, the unification require things like blocks inside parameter
lists... technically doable, but, well, it's a long story, but it
encourages some bad practices, if you have the "multiple bodies" or
"template-defined parameters" (see in ZipScript) or whatever we call
it feature.

> see below (response to JavaScript).
>
>
>
> So here's a rough template language design brainstorming session:
>
> Directives:
>
> Both user-defined and builtins use [#] and share the same "namespace".
> User-defined directives cannot override builtins.
>
> [#foo arg1, arg2 as var1, var2]body[/#foo]
> Call directive foo with params arg1 and arg2, introducing new "loop"
> vars var1 and var2 to body.
>
> [#foo arg1, arg2 as arg3, arg4/]
> Call directive foo with params arg1 and arg2, introducing new vars var1
> and var2 to the parent scope. Of course, if #foo requires a body, this
> should throw an exception somewhere.
>
> [#macro foo, arg1, arg2 as var1, var2]
>    stuff
>    [#set var1=blah]
>    [#set var2=blah]
>    stuff
> [/#macro]
> Replaces macro foo with a directive that uses params arg1 and arg2, and
> introduces vars var1 and var2. var1 and var2 have C-like "call by
> reference" semantics (as opposed to Java's "call by value" semantics),
> i.e. setting var1 actually sets the loop variable.

Yip, that's what I did (on paper, I mean); by value VS by reference.

> [#macro foo, arg1=dv, ...args as var1, ...vars]
>    [#list args as arg]stuff[/#list]
>    [#list vars as var][#set var=blah][/#list]
> [/#macro]
> Example showcasing variadic parameters and default parameters. "vars" is
> a list of references, so that in [#list vars as var], "var" is a
> reference, so [#set var=...] works as you'd expect.

Yes. Actually, I also allowed named variadic parameters. Very very
useful feature. (And something *similar* to that is painfully missing
from most compiled languages. Like, this lack of true named parameters
is why dependency injection via constructor arguments sucks.)

> Functions:
>
> Both builtin and user-defined functions share the exact same syntax.
> Whether builtins are overridable should be configurable (see below).

(Configurable language rules... I would allow it only if you define a
new template language... that could/should be made easy, but still,
you have to give it another name.)

> There are two forms that the user can use: the familiar Java prefix
> style, or the FreeMarker suffix style.
>
> To try to keep the syntax as consistent as possible, I'm using "#" for
> template functions. So to the user, "#" means "template directive/function".

I didn't do that, among others because then you can just write f(x),
you have to write #f(x). So I just used | for doing things like x|f.
But, I'm not saying it's wrong... depends on everything else.
(Because, at least for me, designing a good language is an endless
running of circles... It's like, I pick a particular problem, find a
nice solution for it, and go on to the next problem. I will happily do
that for while, but then the decisions I made start to conflict with
each other on some twisted ways (even on humiliating, petty ways, like
you run out of good symbols...). So then comes "Oh, but I can't do
feature Z the way I find it's the best, because then it clashes with
feature Y. Well, then I rather change feature Y a bit... hmmm, too bad
Y is uglier now, but we are at least OK. Hey, no, this modified Y now
interferes with feature X!". And so on... but after long suffering and
many painful language distortions, I end up with a (hopefully)
consistent language. Then I look at it, and decide that I don't like
it, and I rather run another "circle", means restarting from 0. Then I
somehow end up with something totally different. And so on... I can
generate tons of template languages this way. :) )

> ${#blah(x)}
> Equivalent to FTL expression: ${x?blah}.
>
> ${x#blah}
> Equivalent to FTL expression: ${x?blah}.
>
> [#function blah, arg1, arg2]body[/#function]
> Redefines blah function.
>
> ${#blah(arg1, arg2)}
> Equivalent to FTL expression: ${arg1?blah(arg2)}
>
> ${arg1#blah(arg2)}
> Equivalent to FTL expression: ${arg1?blah(arg2)}
>
> [#function blah, arg1=dv, ...args]body[/#function]
> Showcasing variadic parameters and default parameters.
>
> The template language will have very light "bean wrappers",

Light bean wrappers? I don't get that.

> so there's no need for builtins like "substring" or "contains".
[snip]

> Perhaps JavaScript is a bad example. It's too simplistic to say that
> something should be dynamic or not, when there are multiple ways
> something can be dynamic. For builtin overriding, I can imagine several
> "dynamic levels" that we can choose:
>
> 1) Allowing builtins to be overridden by anything (and even deleted ala
> setting it to null) within the template
> 2) Allowing builtins to be overridden by a function that matches the
> same interface of the builtin within the template
> 3) Same as (1) or (2) except template engine can be configured not to
> allow builtin overriding
> 4) Same as (1) except builtins can only be overridden during
> configuration (from Java)
> 5) Same as (2) except builtins can only be overridden during
> configuration (from Java) and the interface semantics can be more
> precise with the static type checking
> 6) Same as any of the above but allow only non-"core" builtins to be
> overwritten, where a "core" builtin would be eval, interpret, etc.
> 7) Cannot be overwritten, period - not even a Java API to do so (status quo)

BTW, I think that in general, you should try avoid overriding and
hiding anything by anything, because it's confusing. The exceptions
are the use-cases that explicitly build on some kind of overriding,
like subclassing in OOP, or "slots" in some template languages. But
there should be an effort to exclude the possibility of accidental
overrides (for that reason the Java language should require the usage
of @Override, but that would be non-BC.).

>> > And since it's the user that's overriding them, he knows the exact
>> > semantics of it, so I don't see how it can be confusing at all.
>>
>> Who is "the user"? Because it's certainly not one guy, rather a few.
>> Even if it's one guy, certainly it will be another one a few years
>> later. Not to mention the tendency of people to forget things they
>> did, especially if they participate in several projects over the
>> years. So, what going to happen is that the new guy or a some who just
>> has forgotten things will Google things, opens the FreeMarker Manual,
>> see what built-ins are available and what they do, but... oops. (Then
>> you can continue with supporting IDE-s and other text editors when you
>> have a custom set of built-ins. It's possible if you expose some API-s
>> that help the plugin authors, but, yet another place where
>> customization can come back to you.)
>>  
>
> That's a problem with code in general and hardly an argument for keeping
> builtins unconfigurable.

Surely it's a general problem, and that's why I try to avoid such
things in general. Part of that general effort is disallowing built-in
overriding... in FM at least, because it's a single-language engine.

> You could easily mention in the docs that builtins can be redefined
> in user code (whether during configuration or within the template).

I would, still that only had a very limited effect... (Unless I put
flashing red warning box at each built-in reference pages...)

> And I don't find the IDE support argument very convincing. If
> builtins are configurable in Java, then we have javadocs and method
> signatures that can provide hints.

Sure, but it's still harder to solve... that's was the point I tried
to make. Think about simple syntax-highlighters, especially those that
are not Java applications. Now you just can fill some regexps that
match the built-in names (sure, you have to extend that for some new
releases). So it's a disadvantage, but of course maybe something that
you are willing to take.

> If builtins can be overridden within the template, well that's just
> the nature of dynamic languages, although with very good type
> inferencing, editor support is somewhat possible (there are editors
> out there that provide decent type/param inferencing for certain
> dynamic languages).

As far as they can... which is often not that much in practice. The
reason is that if you start to really utilize that you are using a
dynamic language (and in principle you should, otherwise why don't
just use a static one) then, basically for the same reason it couldn't
be compiled like a usual static language, the IDE can't find out
what's going on. (BTW, part of my design goals was making the language
less dynamic.)

>> > IMO, there are relatively few builtins that can be considered as core
>> > operators: eval, type builtins (int, float, etc.), interpret, and some
>> > others. In fact, I would have those particular builtins be actual core
>> > language operators rather than "builtins". The rest are hardly related
>> > to the core and should be fully customizable.
>>
>> A design goal with a fat set of core "methods" (in FM they are the
>> "built-ins:, and the # directives) is that the wherever the user
>> writes a template, he can be sure they are there, and he can access
>> them immediately. He doesn't even have to suffer with importing
>> something like, I don't know, "fm://utils" and assign it to a prefix,
>> which BTW can be quite annoying if you are working with many little
>> independent template fragments (message templates, UI bits in a CMS,
>> etc.). Also he doesn't need to wonder whether, like, HTML escaping is
>> a core method or a utility method. But of course, splitting the
>> out-of-the-box methods into core and utility groups has its advantages
>> too. But this is about seeking compromises. I actually went back and
>> forth between fat-core and thin-core + utils design, but currently I
>> would go for fat-core. But that decision very much depends on what
>> tricks you find out to avoid the earlier mentioned name clashes.
>>  
>
> I'm fine with plenty of builtins. You can have a small set of core
> builtins and then libraries that provide other "builtins" that are
> autoimported into the same "namespace". Then allow the user to configure
> exactly what libraries are autoimported (with the default possibly being
> importing everything).

How is auto-importing into the same namespace less problematic
regarding the name clashes than having a big core library?

> In fact, I'd like the "standard library" to be
> much bigger.
>
> Regards, Yuh-Ruey

--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Yuh-Ruey Chen

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Daniel Dekany wrote:

> Tuesday, September 15, 2009, 11:37:15 AM, Yuh-Ruey Chen wrote:
>
> [snip]
> > I do like the idea of a minimal design that can be extended into custom
> > template languages, so I very much like to see what you have in mind :)
> >
> > I'm actually not too bothered with the fact that there are builtins or
> > that the syntax is a bit odd-looking.
>
> It's not that odd-looking... consider "?" as ".", that has something
> above it. Both is a sentence-ending punctuation character.
>  

In Java-land, the "?" means conditional, so at first glance, it looks
like some weird conditional statement. But I think we both agree that it
does look odd.

> > But I just don't think builtins functions should be treated
> > specially from user-defined functions. Same with builtin directives
> > vs. user-defined directives (more on this later). Builtin and
> > user-defined functions should have a single unified syntax. Right
> > now, builtin functions use the suffix "?" syntax and can't be
> > treated as first-class objects (can't be passed around), while
> > user-defined functions are actually in the data model and are
> > first-class objects.
>
> I agree with that... but note that treating the built-in
> directives/functions/methods/whatever-you-call-them is not possible
> for all of them, because some of them has before-runtime effects.
> (Anyway, in such cases I planned to drop an exception if and when you
> try to call them. So you still can get the thing as a value, and,
> like, query it's name and namespace, but you can't call it.)
>  

Yes, there are a couple directives that take effect before the
evaluation of the template. #ftl configures the template. #noparse,
#compress, #t, #lt, #rt, and #nt affect parsing. Maybe these directives
should have a slightly different syntax to denote this difference, e.g.
[#ftl#] or [#t#] (similar to <?xml-processing-instruction?>).

But I'm not aware of any builtin functions that have such effects.

> > Adding functions to the data model (or shared vars) always feels a bit
> > clunky to me, because it does collide with the rest of the data model.
>
> Yes. But later ?new and #import was introduced to counter that
> tradition.

I'm just not sure if functions should even belong in the data model at
all. I'd rather they be in their own "namespace" (or in the same one as
the builtins). There's a higher chance of accidental collision if
they're in the data model.

> (BTW, one of the big problems of FM is that the whole "FTL
> library" thing is not very streamlined... For example, you can't just
> drop a someoneelsesftllibrary.jar into the classpath of your app., and
> then #import it. Things like that...)
>  

ClassTemplateLoader doesn't do this for you? I haven't actually used
that class, so I have no idea.

> > So user-defined functions can either collide with the data model or the
> > builtin functions, and I think going with the latter is a both a cleaner
> > and safer design.
>
> *If* that's the only two possibility, I agree.
>  

You can put them in their own namespace, but considering the minimal
overlap with core builtins (there shouldn't be many) and the requiring
of a slightly different syntax, I don't think it's worth it.

> > Cleaner because the semantics and syntax of all functions are
> > unified (hopefully leading to cleaner code as well), and safer
> > because the data model is much more variable then the list of
> > functions (e.g. if I have a function "foo", it's more likely that
> > some data model with a "foo" to collide with it than there would be
> > another user-defined function named "foo" to collide with it).
> >
> > Now to unifying user-defined and builtin directives. There are other
> > syntactical differences besides the "#" vs. "@". Some like #assign and
> > #if can't be done with user-defined directives. And unless we want a
> > XML-like verboseness ala JSTL's choose/when, there's not a good way
> > around it (though I'm trying to think of a way they could be
> > user-defined yet not verbose).
>
> Yeah, that's the other tricky part of the unification... You will have
> to add some extra features to your template language, that you maybe
> wouldn't add otherwise. Anyway, I found that it wasn't a big problem
> in practice. Like, I wanted out-parameters feature anyway, and
> something like "set target=source" can be seen as an optional
> shorthand for an application of that. But I don't think it's wise to
> allow the usage of that particular shorthand for user-defined stuff
> (but it's really easy to allow it technically... actually, the extra
> work is disallowing it). And that wasn't the point anyway... the point
> is that *semantically* the "set x=1" is nothing special, it's really
> just "set 1; x". Hence, the "=" thing itself is no in the way if you
> want to call dynamically something that uses that.
>  

So "set x=1" would make sense to the C/Java developer, while "set 1; x"
would not. How about something like this then - reverse the out-params
location and use ":" instead ";":

[#set x : 3]
[#list x : sequence]
[#import foo.ftl]
[#import foo : foo.ftl]

Also, we could just get rid of "using" in #visit and #recurse, treating
"namespace" is an optional param:

[#recurse doc]
[#recurse doc, namespace]

There's no equivalent for [#recurse] and [#recurse using namespace], but
since that is just syntactic sugar for [#recurse .node], it's hardly a loss.

That leaves #if/#else/#elseif, and #switch/#case/#default as the only
directives that require special parsing (besides the ones the affect
parsing itself, noted above).

> > But what about #list and some other directives that use the "as"
> > keyword?
>
> Back then I decided to get rid of "as", "in" and such, and just use
> the unified syntax (";"). Since the expression language clearly
> separate the in- and out-parameters (with ";"), it's obvious which one
> is the source, and which one declare the block-scope variable. Now
> there is a compromise here: "list foo as bar" is more telling than
> "list foo; bar". I to find something better instead of ";" but
> whenever I did it always spoiled something else that I found to be a
> bigger problem... so currently it's ";". So, back to the compromise, I
> found it's not a that big compromise eventually, if you assume the
> user will face a ";" when using some custom macros anyway. Then it's
> just better that there is only one syntax he has to learn: use ";",
> end of story.
>  

Understandable, but there's room for improvement :)

> The other possibility is to allow declaring the usage of "as" or "in"
> in the formal parameter list of the macro definitions... only,
> depending on what purpose the macro has, you may want another
> keyword... which, you won't get, custom keywords. I don't think it's
> need to go into it why not...
>  

Yeah not a good idea...

> > These directives use the "as" keyword in two ways: introducing
> > a new local (loop) variable (if it requires an end tag), or introducing
> > a variable to the template's scope (if it cannot have an end tag).
> > Meanwhile user-defined directives must use the odd semicolon syntax to
> > introduce new local variables, and cannot introduce template-scope
> > variables. I think there is room for unification here.
> >
> > As to whether it's a good idea treat builtins and user-defined functions
> > and directives the same, it should at the very least be configurable -
>
> Hardly. To unify them, you need to touch some quite fundamental rules
> of the language. In FTL, directives meant to generating markup (hence
> they kind of look like HTML tags), while other expressions (like
> function calls) aren't. The importance of this shows when you apply
> #escape; it will not escape the output of directives. Also, in
> FreeMarker only directives can return the result progressively (i.e.,
> they start to output it before it's complete). So, what I'm saying,
> that in the case of FreeMarker there is fundamental difference between
> the two. (I'm not saying there should be... as I said, in my planned
> solution there isn't. But of course, that has some painful
> consequences too...)
>  

Oops, I meant to say "builtin and user-defined functions, and builtin
and user-defined directives". I'm not suggesting that functions and
directives should be unified.

> BTW, the unification require things like blocks inside parameter
> lists... technically doable, but, well, it's a long story, but it
> encourages some bad practices, if you have the "multiple bodies" or
> "template-defined parameters" (see in ZipScript) or whatever we call
> it feature.
>  

Huh, never heard of ZipScript before - I'll check it out...

> > [#macro foo, arg1=dv, ...args as var1, ...vars]
> >    [#list args as arg]stuff[/#list]
> >    [#list vars as var][#set var=blah][/#list]
> > [/#macro]
> > Example showcasing variadic parameters and default parameters. "vars" is
> > a list of references, so that in [#list vars as var], "var" is a
> > reference, so [#set var=...] works as you'd expect.
>
> Yes. Actually, I also allowed named variadic parameters. Very very
> useful feature. (And something *similar* to that is painfully missing
> from most compiled languages. Like, this lack of true named parameters
> is why dependency injection via constructor arguments sucks.)
>  

BTW, Python goes pretty extreme with regards to flexibility here:

def foo(*args) # variadic function, rest params are stored in args as a list
def foo(**args) # variadic function, named rest params are stored in
args as a map from param name to param value
def foo(*args, **kwargs) # combines the above two
def foo(arg1, arg2, *args) # just showing that you can use rest params
with normal params
def foo(arg1, arg2=val) # optional named param
def foo(*args, arg=val) # variadic function; if arg is specified, it
must be a name=value pair (cannot be a positional param)
def foo(*, arg1=val1, arg2=val2) # non-variadic function with
non-positional params

> > There are two forms that the user can use: the familiar Java prefix
> > style, or the FreeMarker suffix style.
> >
> > To try to keep the syntax as consistent as possible, I'm using "#" for
> > template functions. So to the user, "#" means "template directive/function".
>
> I didn't do that, among others because then you can just write f(x),
> you have to write #f(x). So I just used | for doing things like x|f.
>  

The problem with that it that the function looks like it's part of the
data model. Also, it can be incompatible with other JVM languages that
allow class-less functions to be defined, tying FreeMarker too closely
with Java.

On a related note, I think it would be better to not treat FM namespaces
like any other hash, making it look like it's part of the data model.
How about using ":" instead:

[#ns:directive]

${#ns:function()} or ${ns:function()}

${expr#ns:function} or ${expr?ns:function} or ${expr|ns:function}

> But, I'm not saying it's wrong... depends on everything else.
> (Because, at least for me, designing a good language is an endless
> running of circles... It's like, I pick a particular problem, find a
> nice solution for it, and go on to the next problem. I will happily do
> that for while, but then the decisions I made start to conflict with
> each other on some twisted ways (even on humiliating, petty ways, like
> you run out of good symbols...). So then comes "Oh, but I can't do
> feature Z the way I find it's the best, because then it clashes with
> feature Y. Well, then I rather change feature Y a bit... hmmm, too bad
> Y is uglier now, but we are at least OK. Hey, no, this modified Y now
> interferes with feature X!". And so on... but after long suffering and
> many painful language distortions, I end up with a (hopefully)
> consistent language. Then I look at it, and decide that I don't like
> it, and I rather run another "circle", means restarting from 0. Then I
> somehow end up with something totally different. And so on... I can
> generate tons of template languages this way. :) )
>  

I totally get you - I've had my share of experience with designing
languages, and it's really a cycle of eurekas followed by "oh wait"
followed by eureka, ad infinitum.

> > The template language will have very light "bean wrappers",
>
> Light bean wrappers? I don't get that.
>  

Basically the only object wrapper is the one that allows you to access
Java object fields and methods reflectively. No custom "scalars",
"sequences", "hashes", etc. and thus no nee to builtins like "substring"
or "contains".

> BTW, I think that in general, you should try avoid overriding and
> hiding anything by anything, because it's confusing. The exceptions
> are the use-cases that explicitly build on some kind of overriding,
> like subclassing in OOP, or "slots" in some template languages. But
> there should be an effort to exclude the possibility of accidental
> overrides (for that reason the Java language should require the usage
> of @Override, but that would be non-BC.).
>  

I agree to a certain extent, but to me it really depends on the
situation. For ex, when I'm programming in Java, I try to be a strict as
possible to take advantage of the static checking, but when I'm using
Python, I just generally follow best practices and rely on unit tests.
FreeMarker is somewhere between the two - dynamic yet trying to be
rigid. As I noted, the spectrum between "dynamic" and "static" is wide
and there are plenty of advantages and disadvantages on each extreme. So
exactly what you pick is a matter of philosophical preference. And I
personally lean toward "configurable dynamic-ness" where the language
can be as dynamic or as rigid as the user wants.

> > And I don't find the IDE support argument very convincing. If
> > builtins are configurable in Java, then we have javadocs and method
> > signatures that can provide hints.
>
> Sure, but it's still harder to solve... that's was the point I tried
> to make. Think about simple syntax-highlighters, especially those that
> are not Java applications. Now you just can fill some regexps that
> match the built-in names (sure, you have to extend that for some new
> releases). So it's a disadvantage, but of course maybe something that
> you are willing to take.
>
> > If builtins can be overridden within the template, well that's just
> > the nature of dynamic languages, although with very good type
> > inferencing, editor support is somewhat possible (there are editors
> > out there that provide decent type/param inferencing for certain
> > dynamic languages).
>
> As far as they can... which is often not that much in practice. The
> reason is that if you start to really utilize that you are using a
> dynamic language (and in principle you should, otherwise why don't
> just use a static one) then, basically for the same reason it couldn't
> be compiled like a usual static language, the IDE can't find out
> what's going on. (BTW, part of my design goals was making the language
> less dynamic.)
>  

IDE support isn't a big issue IMO. To me, there are 2 main things the
IDEs can provide: 1) refactoring/boilerplate aid, and 2) syntax
highlighting/visual assist. For (1), only verbose languages (like Java)
really benefit from this. And for (2), syntax highlighting is typically
good enough, with any extra visual assistance like "intellisense" just
being cake frosting.

> >> A design goal with a fat set of core "methods" (in FM they are the
> >> "built-ins:, and the # directives) is that the wherever the user
> >> writes a template, he can be sure they are there, and he can access
> >> them immediately. He doesn't even have to suffer with importing
> >> something like, I don't know, "fm://utils" and assign it to a prefix,
> >> which BTW can be quite annoying if you are working with many little
> >> independent template fragments (message templates, UI bits in a CMS,
> >> etc.). Also he doesn't need to wonder whether, like, HTML escaping is
> >> a core method or a utility method. But of course, splitting the
> >> out-of-the-box methods into core and utility groups has its advantages
> >> too. But this is about seeking compromises. I actually went back and
> >> forth between fat-core and thin-core + utils design, but currently I
> >> would go for fat-core. But that decision very much depends on what
> >> tricks you find out to avoid the earlier mentioned name clashes.
> >>  
> >
> > I'm fine with plenty of builtins. You can have a small set of core
> > builtins and then libraries that provide other "builtins" that are
> > autoimported into the same "namespace". Then allow the user to configure
> > exactly what libraries are autoimported (with the default possibly being
> > importing everything).
>
> How is auto-importing into the same namespace less problematic
> regarding the name clashes than having a big core library?
>  

The only thing I'm proposing here is modularizing the library into
separate core/builtin libraries. This will have no effect to the typical
user, since all these core libraries are imported automatically, but I'm
suggesting the ability for advanced users (i.e. making a derivative
template language) to configure exactly which libraries are auto-imported.

So we can have a larger library, yet import a relatively small amount by
default.

Regard, Yuh-Ruey

------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Daniel Dekany

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Wednesday, September 16, 2009, 12:21:47 PM, Yuh-Ruey Chen wrote:

> Daniel Dekany wrote:
>> Tuesday, September 15, 2009, 11:37:15 AM, Yuh-Ruey Chen wrote:
>>
>> [snip]
>> > I do like the idea of a minimal design that can be extended into custom
>> > template languages, so I very much like to see what you have in mind :)
>> >
>> > I'm actually not too bothered with the fact that there are builtins or
>> > that the syntax is a bit odd-looking.
>>
>> It's not that odd-looking... consider "?" as ".", that has something
>> above it. Both is a sentence-ending punctuation character.
>>  
>
> In Java-land, the "?" means conditional, so at first glance, it looks
> like some weird conditional statement. But I think we both agree that it
> does look odd.

Yeah, but mostly only because it looks like the ternary operator you
mentioned. (Which brings up another typical problem in language
design... even if you don't run out of good (telling, suggestive)
symbols within your own language, you also have to respect the syntax
of Java. And, maybe even of Groovy, etc. Actually, not following them
is often acceptable, but using something that looks like something in
Java, but does something different...)

>> > But I just don't think builtins functions should be treated
>> > specially from user-defined functions. Same with builtin directives
>> > vs. user-defined directives (more on this later). Builtin and
>> > user-defined functions should have a single unified syntax. Right
>> > now, builtin functions use the suffix "?" syntax and can't be
>> > treated as first-class objects (can't be passed around), while
>> > user-defined functions are actually in the data model and are
>> > first-class objects.
>>
>> I agree with that... but note that treating the built-in
>> directives/functions/methods/whatever-you-call-them is not possible
>> for all of them, because some of them has before-runtime effects.
>> (Anyway, in such cases I planned to drop an exception if and when you
>> try to call them. So you still can get the thing as a value, and,
>> like, query it's name and namespace, but you can't call it.)
>>  
>
> Yes, there are a couple directives that take effect before the
> evaluation of the template. #ftl configures the template. #noparse,
> #compress, #t, #lt, #rt, and #nt affect parsing. Maybe these directives
> should have a slightly different syntax to denote this difference, e.g.
> [#ftl#] or [#t#] (similar to <?xml-processing-instruction?>).

Been there... I ended up on the standpoint that it doesn't worth it
(unless you have tons of fancy "pre-processor" directives and like in
which case it becomes crucial to visually separate what is executed in
the 1st, and what in the 2nd phase). It adds visual clutter, and is
one more thing to remember for most users... you language looks more
complex, more confusing. All that for a little theoretical clarity,
doesn't worth it.

> But I'm not aware of any builtin functions that have such effects.

Not that it's impossible that one day you want to add a such
function...

>> > Adding functions to the data model (or shared vars) always feels a bit
>> > clunky to me, because it does collide with the rest of the data model.
>>
>> Yes. But later ?new and #import was introduced to counter that
>> tradition.
>
> I'm just not sure if functions should even belong in the data model at
> all. I'd rather they be in their own "namespace"

Exactly... Java Language has the trick for it (methods VS fields), and
I applied exactly the same trick: if you call it, the name is to be
searched in the method namespace, otherwise in the plain-variable
namespace. It makes getting methods as values a bit tricky (yet
possible: currying), but in exchange you get a lot of benefits. And
the same trick you can apply on the data-model, so Map items doesn't
conflict with Map methods anymore.

Now, at this point, let me ask, why are you so interested in template
language design? I mean, it looks like you have given considerable
amount of thought to the topic. So, what are you up to?

> (or in the same one as
> the builtins). There's a higher chance of accidental collision if
> they're in the data model.
>
>> (BTW, one of the big problems of FM is that the whole "FTL
>> library" thing is not very streamlined... For example, you can't just
>> drop a someoneelsesftllibrary.jar into the classpath of your app., and
>> then #import it. Things like that...)
>>  
>
> ClassTemplateLoader doesn't do this for you? I haven't actually used
> that class, so I have no idea.
>
>> > So user-defined functions can either collide with the data model or the
>> > builtin functions, and I think going with the latter is a both a cleaner
>> > and safer design.
>>
>> *If* that's the only two possibility, I agree.
>>  
>
> You can put them in their own namespace, but considering the minimal
> overlap with core builtins (there shouldn't be many) and the requiring
> of a slightly different syntax, I don't think it's worth it.
>
>> > Cleaner because the semantics and syntax of all functions are
>> > unified (hopefully leading to cleaner code as well), and safer
>> > because the data model is much more variable then the list of
>> > functions (e.g. if I have a function "foo", it's more likely that
>> > some data model with a "foo" to collide with it than there would be
>> > another user-defined function named "foo" to collide with it).
>> >
>> > Now to unifying user-defined and builtin directives. There are other
>> > syntactical differences besides the "#" vs. "@". Some like #assign and
>> > #if can't be done with user-defined directives. And unless we want a
>> > XML-like verboseness ala JSTL's choose/when, there's not a good way
>> > around it (though I'm trying to think of a way they could be
>> > user-defined yet not verbose).
>>
>> Yeah, that's the other tricky part of the unification... You will have
>> to add some extra features to your template language, that you maybe
>> wouldn't add otherwise. Anyway, I found that it wasn't a big problem
>> in practice. Like, I wanted out-parameters feature anyway, and
>> something like "set target=source" can be seen as an optional
>> shorthand for an application of that. But I don't think it's wise to
>> allow the usage of that particular shorthand for user-defined stuff
>> (but it's really easy to allow it technically... actually, the extra
>> work is disallowing it). And that wasn't the point anyway... the point
>> is that *semantically* the "set x=1" is nothing special, it's really
>> just "set 1; x". Hence, the "=" thing itself is no in the way if you
>> want to call dynamically something that uses that.
>>  
>
> So "set x=1" would make sense to the C/Java developer, while "set 1; x"
> would not.

Nobody should write "set 1; x", it's that what "set x=1" means. I know
it's a bit non-uniform this way, but you hardly ever can do something
both practically and on a totally uniform/generic way on the same
time.

> How about something like this then - reverse the out-params
> location and use ":" instead ";":
>
> [#set x : 3]
> [#list x : sequence]
> [#import foo.ftl]
> [#import foo : foo.ftl]

/-: I think for assignment everyone just wants to write "=". But then,
there are directives that do have out-params but are still not about
assignment. So there you will just use the unified syntax, and for set
the special syntax.

> Also, we could just get rid of "using" in #visit and #recurse, treating
> "namespace" is an optional param:
>
> [#recurse doc]
> [#recurse doc, namespace]

This kind of usage of keywords it actually the result of not using
named parameters. I mean, [#recurse doc, namespace] is not very
telling, [#recurse doc using namespace] is. But, using named
parameters, [#recurse doc, using: namespace] would be too...

> There's no equivalent for [#recurse] and [#recurse using namespace],

With named parameters there is: [#recurse using: namespace]

> but since that is just syntactic sugar for [#recurse .node], it's
> hardly a loss.
>
> That leaves #if/#else/#elseif, and #switch/#case/#default as the only
> directives that require special parsing (besides the ones the affect
> parsing itself, noted above).

They are not *that* special necessarily. In FTL only #if had an
end-tag, not the #else/#leseif, which makes then quite much special.
But that can be avoided with a different syntax. Like, in
WebMacro-style (which is basically JavaScript-style) there is no such
kind of problem whatsoever. The only speciality that remains is the
way how if/else/elseif changes the control flow. Like, a successful
#if skips all following #else/#elseif *siblings*. It's a bit extreme
that node has such control over his siblings (as opposed to over its
children).

>> > But what about #list and some other directives that use the "as"
>> > keyword?
>>
>> Back then I decided to get rid of "as", "in" and such, and just use
>> the unified syntax (";"). Since the expression language clearly
>> separate the in- and out-parameters (with ";"), it's obvious which one
>> is the source, and which one declare the block-scope variable. Now
>> there is a compromise here: "list foo as bar" is more telling than
>> "list foo; bar". I to find something better instead of ";" but
>> whenever I did it always spoiled something else that I found to be a
>> bigger problem... so currently it's ";". So, back to the compromise, I
>> found it's not a that big compromise eventually, if you assume the
>> user will face a ";" when using some custom macros anyway. Then it's
>> just better that there is only one syntax he has to learn: use ";",
>> end of story.
>>  
>
> Understandable, but there's room for improvement :)

Maybe, maybe... but as I said, you improve something, and then realize
you have to un-improve something else because of that.

>> The other possibility is to allow declaring the usage of "as" or "in"
>> in the formal parameter list of the macro definitions... only,
>> depending on what purpose the macro has, you may want another
>> keyword... which, you won't get, custom keywords. I don't think it's
>> need to go into it why not...
>>  
>
> Yeah not a good idea...
>
>> > These directives use the "as" keyword in two ways: introducing
>> > a new local (loop) variable (if it requires an end tag), or introducing
>> > a variable to the template's scope (if it cannot have an end tag).
>> > Meanwhile user-defined directives must use the odd semicolon syntax to
>> > introduce new local variables, and cannot introduce template-scope
>> > variables. I think there is room for unification here.
>> >
>> > As to whether it's a good idea treat builtins and user-defined functions
>> > and directives the same, it should at the very least be configurable -
>>
>> Hardly. To unify them, you need to touch some quite fundamental rules
>> of the language. In FTL, directives meant to generating markup (hence
>> they kind of look like HTML tags), while other expressions (like
>> function calls) aren't. The importance of this shows when you apply
>> #escape; it will not escape the output of directives. Also, in
>> FreeMarker only directives can return the result progressively (i.e.,
>> they start to output it before it's complete). So, what I'm saying,
>> that in the case of FreeMarker there is fundamental difference between
>> the two. (I'm not saying there should be... as I said, in my planned
>> solution there isn't. But of course, that has some painful
>> consequences too...)
>>  
>
> Oops, I meant to say "builtin and user-defined functions, and builtin
> and user-defined directives". I'm not suggesting that functions and
> directives should be unified.

I see.

>> BTW, the unification require things like blocks inside parameter
>> lists... technically doable, but, well, it's a long story, but it
>> encourages some bad practices, if you have the "multiple bodies" or
>> "template-defined parameters" (see in ZipScript) or whatever we call
>> it feature.
>>  
>
> Huh, never heard of ZipScript before - I'll check it out...
>
>> > [#macro foo, arg1=dv, ...args as var1, ...vars]
>> >    [#list args as arg]stuff[/#list]
>> >    [#list vars as var][#set var=blah][/#list]
>> > [/#macro]
>> > Example showcasing variadic parameters and default parameters. "vars" is
>> > a list of references, so that in [#list vars as var], "var" is a
>> > reference, so [#set var=...] works as you'd expect.
>>
>> Yes. Actually, I also allowed named variadic parameters. Very very
>> useful feature. (And something *similar* to that is painfully missing
>> from most compiled languages. Like, this lack of true named parameters
>> is why dependency injection via constructor arguments sucks.)
>>  
>
> BTW, Python goes pretty extreme with regards to flexibility here:
>
> def foo(*args) # variadic function, rest params are stored in args as a list
> def foo(**args) # variadic function, named rest params are stored in
> args as a map from param name to param value
> def foo(*args, **kwargs) # combines the above two
> def foo(arg1, arg2, *args) # just showing that you can use rest params
> with normal params
> def foo(arg1, arg2=val) # optional named param
> def foo(*args, arg=val) # variadic function; if arg is specified, it
> must be a name=value pair (cannot be a positional param)
> def foo(*, arg1=val1, arg2=val2) # non-variadic function with
> non-positional params
>
>> > There are two forms that the user can use: the familiar Java prefix
>> > style, or the FreeMarker suffix style.
>> >
>> > To try to keep the syntax as consistent as possible, I'm using "#" for
>> > template functions. So to the user, "#" means "template directive/function".
>>
>> I didn't do that, among others because then you can just write f(x),
>> you have to write #f(x). So I just used | for doing things like x|f.
>>  
>
> The problem with that it that the function looks like it's part of the
> data model.

Yes, but since you seldom has top-level methods in the data-model, you
can assume that any top-level f() is the calling of a core method.
That was one of the "painful" tricks I did.

> Also, it can be incompatible with other JVM languages that
> allow class-less functions to be defined, tying FreeMarker too closely
> with Java.
>
> On a related note, I think it would be better to not treat FM namespaces
> like any other hash, making it look like it's part of the data model.

Yeah... but unfortunately, that has it's drawbacks to. Like, since
namespace *are* hashes, you may want to pass them around as values.
How do you refer to them then? "ns:.root" or something... awkward. But
whatever... However funny is, the bigger problem I ran into is that
there is pretty big competition for the ":" symbol. Named parameters
want that, ternary operator want that... and if more of them has it,
you usually end up with an ambiguous syntax. So, surely in general
it's desirable to separate namespace prefixes from other variables,
but unfortunately at the end of that circle (referring to the "running
circles" I wrote about earlier) you may end up without that.

> How about using ":" instead:
>
> [#ns:directive]
>
> ${#ns:function()} or ${ns:function()}
>
> ${expr#ns:function} or ${expr?ns:function} or ${expr|ns:function}

Note that for the last line dot works too: expr#ns.function, etc.

>> But, I'm not saying it's wrong... depends on everything else.
>> (Because, at least for me, designing a good language is an endless
>> running of circles... It's like, I pick a particular problem, find a
>> nice solution for it, and go on to the next problem. I will happily do
>> that for while, but then the decisions I made start to conflict with
>> each other on some twisted ways (even on humiliating, petty ways, like
>> you run out of good symbols...). So then comes "Oh, but I can't do
>> feature Z the way I find it's the best, because then it clashes with
>> feature Y. Well, then I rather change feature Y a bit... hmmm, too bad
>> Y is uglier now, but we are at least OK. Hey, no, this modified Y now
>> interferes with feature X!". And so on... but after long suffering and
>> many painful language distortions, I end up with a (hopefully)
>> consistent language. Then I look at it, and decide that I don't like
>> it, and I rather run another "circle", means restarting from 0. Then I
>> somehow end up with something totally different. And so on... I can
>> generate tons of template languages this way. :) )
>>  
>
> I totally get you - I've had my share of experience with designing
> languages, and it's really a cycle of eurekas followed by "oh wait"
> followed by eureka, ad infinitum.
>
>> > The template language will have very light "bean wrappers",
>>
>> Light bean wrappers? I don't get that.
>>  
>
> Basically the only object wrapper is the one that allows you to
> access Java object fields and methods reflectively. No custom
> "scalars", "sequences", "hashes", etc. and thus no nee to builtins
> like "substring" or "contains".
>
>> BTW, I think that in general, you should try avoid overriding and
>> hiding anything by anything, because it's confusing. The exceptions
>> are the use-cases that explicitly build on some kind of overriding,
>> like subclassing in OOP, or "slots" in some template languages. But
>> there should be an effort to exclude the possibility of accidental
>> overrides (for that reason the Java language should require the usage
>> of @Override, but that would be non-BC.).
>>  
>
> I agree to a certain extent, but to me it really depends on the
> situation. For ex, when I'm programming in Java, I try to be a strict as
> possible to take advantage of the static checking, but when I'm using
> Python, I just generally follow best practices and rely on unit tests.
> FreeMarker is somewhere between the two - dynamic yet trying to be
> rigid. As I noted, the spectrum between "dynamic" and "static" is wide
> and there are plenty of advantages and disadvantages on each extreme. So
> exactly what you pick is a matter of philosophical preference. And I
> personally lean toward "configurable dynamic-ness" where the language
> can be as dynamic or as rigid as the user wants.

Surely that *sounds* like the ideal solution... but I'm not sure yet
if in practice how that will work out. Even a little option to be
un-strict can make things that worked reliably earlier become suddenly
complex and unreliable (because something that doesn't work only in 1%
of cases is immediately not reliable). I would rather think the way
out is remaining strict, but with more powerful type system and like
(see Scala), but we shall see...

>> > And I don't find the IDE support argument very convincing. If
>> > builtins are configurable in Java, then we have javadocs and method
>> > signatures that can provide hints.
>>
>> Sure, but it's still harder to solve... that's was the point I tried
>> to make. Think about simple syntax-highlighters, especially those that
>> are not Java applications. Now you just can fill some regexps that
>> match the built-in names (sure, you have to extend that for some new
>> releases). So it's a disadvantage, but of course maybe something that
>> you are willing to take.
>>
>> > If builtins can be overridden within the template, well that's just
>> > the nature of dynamic languages, although with very good type
>> > inferencing, editor support is somewhat possible (there are editors
>> > out there that provide decent type/param inferencing for certain
>> > dynamic languages).
>>
>> As far as they can... which is often not that much in practice. The
>> reason is that if you start to really utilize that you are using a
>> dynamic language (and in principle you should, otherwise why don't
>> just use a static one) then, basically for the same reason it couldn't
>> be compiled like a usual static language, the IDE can't find out
>> what's going on. (BTW, part of my design goals was making the language
>> less dynamic.)
>>  
>
> IDE support isn't a big issue IMO. To me, there are 2 main things
> the IDEs can provide: 1) refactoring/boilerplate aid, and 2) syntax
> highlighting/visual assist.

Good for you! For me, marking the typos (like in method names) and
auto-completion (especially for parameter lists) is a must-have too. I
just don't have the mental ability of typing without error and
memorizing tons of API-s to the letter... But I think I'm not
completely alone with these.

> For (1), only verbose languages (like Java) really benefit from
> this. And for (2), syntax highlighting is typically good enough,
> with any extra visual assistance like "intellisense" just being cake
> frosting.
>
>> >> A design goal with a fat set of core "methods" (in FM they are the
>> >> "built-ins:, and the # directives) is that the wherever the user
>> >> writes a template, he can be sure they are there, and he can access
>> >> them immediately. He doesn't even have to suffer with importing
>> >> something like, I don't know, "fm://utils" and assign it to a prefix,
>> >> which BTW can be quite annoying if you are working with many little
>> >> independent template fragments (message templates, UI bits in a CMS,
>> >> etc.). Also he doesn't need to wonder whether, like, HTML escaping is
>> >> a core method or a utility method. But of course, splitting the
>> >> out-of-the-box methods into core and utility groups has its advantages
>> >> too. But this is about seeking compromises. I actually went back and
>> >> forth between fat-core and thin-core + utils design, but currently I
>> >> would go for fat-core. But that decision very much depends on what
>> >> tricks you find out to avoid the earlier mentioned name clashes.
>> >>  
>> >
>> > I'm fine with plenty of builtins. You can have a small set of core
>> > builtins and then libraries that provide other "builtins" that are
>> > autoimported into the same "namespace". Then allow the user to configure
>> > exactly what libraries are autoimported (with the default possibly being
>> > importing everything).
>>
>> How is auto-importing into the same namespace less problematic
>> regarding the name clashes than having a big core library?
>>  
>
> The only thing I'm proposing here is modularizing the library into
> separate core/builtin libraries. This will have no effect to the typical
> user, since all these core libraries are imported automatically, but I'm
> suggesting the ability for advanced users (i.e. making a derivative
> template language) to configure exactly which libraries are auto-imported.

Ah, that. Of course, that how it should work.

> So we can have a larger library, yet import a relatively small amount by
> default.
>
> Regard, Yuh-Ruey

--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Yuh-Ruey Chen

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Daniel Dekany wrote:

> Wednesday, September 16, 2009, 12:21:47 PM, Yuh-Ruey Chen wrote:
>
> > Daniel Dekany wrote:
> > Yes, there are a couple directives that take effect before the
> > evaluation of the template. #ftl configures the template. #noparse,
> > #compress, #t, #lt, #rt, and #nt affect parsing. Maybe these directives
> > should have a slightly different syntax to denote this difference, e.g.
> > [#ftl#] or [#t#] (similar to <?xml-processing-instruction?>).
>
> Been there... I ended up on the standpoint that it doesn't worth it
> (unless you have tons of fancy "pre-processor" directives and like in
> which case it becomes crucial to visually separate what is executed in
> the 1st, and what in the 2nd phase). It adds visual clutter, and is
> one more thing to remember for most users... you language looks more
> complex, more confusing. All that for a little theoretical clarity,
> doesn't worth it.
>  

Fair enough. I also don't think it's worth it, and it's unlikely that
there will be many new "parsing directives".

> > But I'm not aware of any builtin functions that have such effects.
>
> Not that it's impossible that one day you want to add a such
> function...
>  

Can you give an example of an operation affecting parsing that would be
better of as a function (within an expression that's evaluated at
runtime!) than as a directive?

> >> > Adding functions to the data model (or shared vars) always feels a bit
> >> > clunky to me, because it does collide with the rest of the data model.
> >>
> >> Yes. But later ?new and #import was introduced to counter that
> >> tradition.
> >
> > I'm just not sure if functions should even belong in the data model at
> > all. I'd rather they be in their own "namespace"
>
> Exactly... Java Language has the trick for it (methods VS fields), and
> I applied exactly the same trick: if you call it, the name is to be
> searched in the method namespace, otherwise in the plain-variable
> namespace. It makes getting methods as values a bit tricky (yet
> possible: currying), but in exchange you get a lot of benefits. And
> the same trick you can apply on the data-model, so Map items doesn't
> conflict with Map methods anymore.
>  

Well that's an odd use of currying. In any case, I don't know what the
future holds for Java's popularity, but the JVM will likely stick around
for a while, so it may not be such a good idea to tie a template
language so closely to Java's quirks. For example, you mention Scala
(which is a language I'm very interested in delving into), and it has
function objects.

> Now, at this point, let me ask, why are you so interested in template
> language design? I mean, it looks like you have given considerable
> amount of thought to the topic. So, what are you up to?
>  

Taking over the world of course.

Seriously, I just have a general interest in programming language
design. And I haven't spent that much time thinking about template
languages in particular - maybe less than half a day's worth with these
emails.

And now a question of my own: do you ever intend to act on any of these
language redesigns? :)

> > Also, we could just get rid of "using" in #visit and #recurse, treating
> > "namespace" is an optional param:
> >
> > [#recurse doc]
> > [#recurse doc, namespace]
>
> This kind of usage of keywords it actually the result of not using
> named parameters. I mean, [#recurse doc, namespace] is not very
> telling, [#recurse doc using namespace] is. But, using named
> parameters, [#recurse doc, using: namespace] would be too...
>  

But what makes [#recurse] or [#visit] so special that it deserves the
same "syntactic attention" as assignment or conditionals? #recurse and
#visit could just be left out of the core and defined in a library (in
Java of course).

To give some perspective: I defined a directive called #let that I use
to create "scopes":

[@let expr; var]
   usage of ${var}
[/@let]

which is a "shortcut" for

[#macro some_name_just_provides_scoping]
   [#set var = expr]
   usage of ${var}
[/#macro]
[@some_name_just_provides_scoping]

It seems "unfair" that [#recurse] or [#visit] get special attention,
when this particular user-defined directive is more "core-like".

> > That leaves #if/#else/#elseif, and #switch/#case/#default as the only
> > directives that require special parsing (besides the ones the affect
> > parsing itself, noted above).
>
> They are not *that* special necessarily. In FTL only #if had an
> end-tag, not the #else/#leseif, which makes then quite much special.
> But that can be avoided with a different syntax. Like, in
> WebMacro-style (which is basically JavaScript-style) there is no such
> kind of problem whatsoever. The only speciality that remains is the
> way how if/else/elseif changes the control flow. Like, a successful
> #if skips all following #else/#elseif *siblings*. It's a bit extreme
> that node has such control over his siblings (as opposed to over its
> children).
>  

One point that I forgot to mention is how builtin directives could omit
the "/" for body-less directives (in fact, I'm not even sure it's
legal?). Which makes #else (among others) special.

Here's a wild suggestion concerning control flow: Add a method to
DirectiveBody that returns a new template (essentially uses the same
context as the current template and is rooted at the directive template
element). Then the user can walk the AST and selectively execute nodes.
That would allow advanced FreeMarker users (from the Java side) to
implement nearly any non-parsing directive they want.

> > Also, it can be incompatible with other JVM languages that
> > allow class-less functions to be defined, tying FreeMarker too closely
> > with Java.
> >
> > On a related note, I think it would be better to not treat FM namespaces
> > like any other hash, making it look like it's part of the data model.
>
> Yeah... but unfortunately, that has it's drawbacks to. Like, since
> namespace *are* hashes, you may want to pass them around as values.
> How do you refer to them then? "ns:.root" or something... awkward. But
> whatever... However funny is, the bigger problem I ran into is that
> there is pretty big competition for the ":" symbol. Named parameters
> want that, ternary operator want that... and if more of them has it,
> you usually end up with an ambiguous syntax. So, surely in general
> it's desirable to separate namespace prefixes from other variables,
> but unfortunately at the end of that circle (referring to the "running
> circles" I wrote about earlier) you may end up without that.
>  

True. Using ":" may also be result in some confusion with XML
namespaces, e.g. ${node["x:foo"]} vs . ${node[x:foo]}.

But still, namespaces colliding with the data model is bad. I can
envision a scenario where such a collision would be hard to detect (in
that no error would be thrown): both the model object named x and a
namespace imported as x have a same "method signature".

> > I agree to a certain extent, but to me it really depends on the
> > situation. For ex, when I'm programming in Java, I try to be a strict as
> > possible to take advantage of the static checking, but when I'm using
> > Python, I just generally follow best practices and rely on unit tests.
> > FreeMarker is somewhere between the two - dynamic yet trying to be
> > rigid. As I noted, the spectrum between "dynamic" and "static" is wide
> > and there are plenty of advantages and disadvantages on each extreme. So
> > exactly what you pick is a matter of philosophical preference. And I
> > personally lean toward "configurable dynamic-ness" where the language
> > can be as dynamic or as rigid as the user wants.
>
> Surely that *sounds* like the ideal solution... but I'm not sure yet
> if in practice how that will work out. Even a little option to be
> un-strict can make things that worked reliably earlier become suddenly
> complex and unreliable (because something that doesn't work only in 1%
> of cases is immediately not reliable). I would rather think the way
> out is remaining strict, but with more powerful type system and like
> (see Scala), but we shall see...
>  

So you want extensibility, but "strict" extensibility. I like the idea,
but again it really depends on the situation and what exactly is
extensible, e.g. if you're designing a template engine that targets
arbitrary template languages, you do want a lot of flexibility, but
within a particular language, not so much. Also note that even the
notoriously strict Java can be fairly dynamic with reflection [abuse].

> > IDE support isn't a big issue IMO. To me, there are 2 main things
> > the IDEs can provide: 1) refactoring/boilerplate aid, and 2) syntax
> > highlighting/visual assist.
>
> Good for you! For me, marking the typos (like in method names) and
> auto-completion (especially for parameter lists) is a must-have too. I
> just don't have the mental ability of typing without error and
> memorizing tons of API-s to the letter... But I think I'm not
> completely alone with these.
>  

Yet dynamic languages that lack extensive IDE support still flourish. To
each, his own.

Regards, Yuh-Ruey

------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Daniel Dekany

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Thursday, September 17, 2009, 10:42:01 AM, Yuh-Ruey Chen wrote:

> Daniel Dekany wrote:
>> Wednesday, September 16, 2009, 12:21:47 PM, Yuh-Ruey Chen wrote:
>>
>> > Daniel Dekany wrote:
>> > Yes, there are a couple directives that take effect before the
>> > evaluation of the template. #ftl configures the template. #noparse,
>> > #compress, #t, #lt, #rt, and #nt affect parsing. Maybe these directives
>> > should have a slightly different syntax to denote this difference, e.g.
>> > [#ftl#] or [#t#] (similar to <?xml-processing-instruction?>).
>>
>> Been there... I ended up on the standpoint that it doesn't worth it
>> (unless you have tons of fancy "pre-processor" directives and like in
>> which case it becomes crucial to visually separate what is executed in
>> the 1st, and what in the 2nd phase). It adds visual clutter, and is
>> one more thing to remember for most users... you language looks more
>> complex, more confusing. All that for a little theoretical clarity,
>> doesn't worth it.
>>  
>
> Fair enough. I also don't think it's worth it, and it's unlikely that
> there will be many new "parsing directives".
>
>> > But I'm not aware of any builtin functions that have such effects.
>>
>> Not that it's impossible that one day you want to add a such
>> function...
>>  
>
> Can you give an example of an operation affecting parsing that would be
> better of as a function (within an expression that's evaluated at
> runtime!) than as a directive?

Examples of such functions are those than return their own location in
the source code, or those that crate a closure from their parameter
expression (for delayed execution).

>> >> > Adding functions to the data model (or shared vars) always feels a bit
>> >> > clunky to me, because it does collide with the rest of the data model.
>> >>
>> >> Yes. But later ?new and #import was introduced to counter that
>> >> tradition.
>> >
>> > I'm just not sure if functions should even belong in the data model at
>> > all. I'd rather they be in their own "namespace"
>>
>> Exactly... Java Language has the trick for it (methods VS fields), and
>> I applied exactly the same trick: if you call it, the name is to be
>> searched in the method namespace, otherwise in the plain-variable
>> namespace. It makes getting methods as values a bit tricky (yet
>> possible: currying), but in exchange you get a lot of benefits. And
>> the same trick you can apply on the data-model, so Map items doesn't
>> conflict with Map methods anymore.
>>  
>
> Well that's an odd use of currying. In any case, I don't know what the
> future holds for Java's popularity, but the JVM will likely stick around
> for a while, so it may not be such a good idea to tie a template
> language so closely to Java's quirks.

Using a separate namespace for the methods and the fields is actually
the feature of the JVM. Not that a language can't chose to hidate
that... But I don't think we will see the fall of the Java Language
earlier than the fall of whole Java (JVM, etc.) thing. Poor Scala has
no chance to take over (in popularity), because it's too difficult to
grasp.

> For example, you mention Scala (which is a language I'm very
> interested in delving into), and it has function objects.

Note that the planned template language do have functions as objects,
only the syntactical trick to get those objects is an extreme case of
currying, where you left all parameters unspecified.

>> Now, at this point, let me ask, why are you so interested in template
>> language design? I mean, it looks like you have given considerable
>> amount of thought to the topic. So, what are you up to?
>>  
> Taking over the world of course.

Great! Then you are in! ;-)

> Seriously, I just have a general interest in programming language
> design. And I haven't spent that much time thinking about template
> languages in particular - maybe less than half a day's worth with these
> emails.
>
> And now a question of my own: do you ever intend to act on any of these
> language redesigns? :)

I do *intend* to. But then, it's not at all sure that I will... /-:
First of all, it's a *lot* of time to release something like this,
secondly I didn't have the impression that any of the key personal
here (but me) was very much enthusiastic about this. They may prefer
continuing gradual evolution instead. Anyway, if I release something,
maybe they will feel like jumping in, so the blame is on me
completely. BTW, it's more than language redesign, I also changed the
whole public API. I suppose I should hold a presentation on the topic
on the next Visigoth Con...

>> > Also, we could just get rid of "using" in #visit and #recurse, treating
>> > "namespace" is an optional param:
>> >
>> > [#recurse doc]
>> > [#recurse doc, namespace]
>>
>> This kind of usage of keywords it actually the result of not using
>> named parameters. I mean, [#recurse doc, namespace] is not very
>> telling, [#recurse doc using namespace] is. But, using named
>> parameters, [#recurse doc, using: namespace] would be too...
>>  
>
> But what makes [#recurse] or [#visit] so special that it deserves the
> same "syntactic attention" as assignment or conditionals?

I guess some people finds it more readable that way, and that's it...

> #recurse and #visit could just be left out of the core and defined
> in a library (in Java of course).

In the case of FM, it's just simpler if everything is just there,
fixed.

> To give some perspective: I defined a directive called #let that I use
> to create "scopes":
>
> [@let expr; var]
>    usage of ${var}
> [/@let]
>
> which is a "shortcut" for
>
> [#macro some_name_just_provides_scoping]
>    [#set var = expr]
>    usage of ${var}
> [/#macro]
> [@some_name_just_provides_scoping]
>
> It seems "unfair" that [#recurse] or [#visit] get special attention,
> when this particular user-defined directive is more "core-like".

I used to say that if you can't implement a core directive using the
same API-s as users can define their own directives, then your
API/design certainly has some issues. This doesn't go to very core
stuff of course...

>> > That leaves #if/#else/#elseif, and #switch/#case/#default as the only
>> > directives that require special parsing (besides the ones the affect
>> > parsing itself, noted above).
>>
>> They are not *that* special necessarily. In FTL only #if had an
>> end-tag, not the #else/#leseif, which makes then quite much special.
>> But that can be avoided with a different syntax. Like, in
>> WebMacro-style (which is basically JavaScript-style) there is no such
>> kind of problem whatsoever. The only speciality that remains is the
>> way how if/else/elseif changes the control flow. Like, a successful
>> #if skips all following #else/#elseif *siblings*. It's a bit extreme
>> that node has such control over his siblings (as opposed to over its
>> children).
>>  
>
> One point that I forgot to mention is how builtin directives could omit
> the "/" for body-less directives (in fact, I'm not even sure it's
> legal?). Which makes #else (among others) special.

The empty-tag "/" and like... If the language knows the called
directive in parsing time (which is surely the case for core
directives), it just knows that it's body-less directive or not. It
could know that for user-defined stuff as well, as far as you don't
use late-binding to the user libraries (i.e., you import them when you
parse the dependent template), but that's usually too restrictive for
a template language. For that reason I prefer the syntax where finding
out such things (i.e., if this is a start-tag or an empty-tag a.k.a.
start-end-tag) doesn't require the knowing of he directives.

Also, #else is not body-less (let alone how it was implemented in
FM... I don't remember how it was). It definitely has body, but it
also has a strange kind of *implied* end-tag.

> Here's a wild suggestion concerning control flow: Add a method to
> DirectiveBody that returns a new template (essentially uses the same
> context as the current template and is rooted at the directive template
> element). Then the user can walk the AST and selectively execute nodes.
> That would allow advanced FreeMarker users (from the Java side) to
> implement nearly any non-parsing directive they want.

That's a possible way of allowing this, yes... Only I'm not very happy
with such rules that can't "declared", rather they are described by
the implementation, also not very happy with custom directives that
change the control flow on an irregular way. I mean, you have a few
core directives that do that, and for those the user will learn they
behave that way. Anyway, for if/elseif/else or attempt/recover (or
try/except/finally) it's just intuitive. But when you look at a
template full of calls to 3rd party directives, you expect they obey
to the regular control flow rules. As of the first thing, "not
declared", there is a solution, that also mitigates the second problem
(being confusing) a bit: directives could be declared as siblings,
means they will be collected by the parser under a common implicit
parent node, and also that the engine will not allow any other kind of
nodes occur between them (like myIf{...}WOMBAT{...}myElse{...}).

>> > Also, it can be incompatible with other JVM languages that
>> > allow class-less functions to be defined, tying FreeMarker too closely
>> > with Java.
>> >
>> > On a related note, I think it would be better to not treat FM namespaces
>> > like any other hash, making it look like it's part of the data model.
>>
>> Yeah... but unfortunately, that has it's drawbacks to. Like, since
>> namespace *are* hashes, you may want to pass them around as values.
>> How do you refer to them then? "ns:.root" or something... awkward. But
>> whatever... However funny is, the bigger problem I ran into is that
>> there is pretty big competition for the ":" symbol. Named parameters
>> want that, ternary operator want that... and if more of them has it,
>> you usually end up with an ambiguous syntax. So, surely in general
>> it's desirable to separate namespace prefixes from other variables,
>> but unfortunately at the end of that circle (referring to the "running
>> circles" I wrote about earlier) you may end up without that.
>>  
>
> True. Using ":" may also be result in some confusion with XML
> namespaces, e.g. ${node["x:foo"]} vs . ${node[x:foo]}.
>
> But still, namespaces colliding with the data model is bad.

Yes... during my latest "circle", I still ended up with that. /-: All
because I ran out of symbols. ":" is definitely taken, as the de-facto
standard operator in the Java-world for key-name separation (used for
Map literals and named parameters) and also as character in the
ternary operator. "." is for plain sub-variables. So... I could chose
some arbitrary operator as separator, like, x@foo, but it looks so
bad, I don't think it would be popular despite it prevents those name
clashes. Which are, IMO, more seldom problems than some would believe,
because:

- The namespace prefixes has lexical scope and are declared at the
  beginning of the template (not strictly so in FM, but whatever),
  so as the template author you surely know what prefixes you have.

- If you want to get a data-model variable with a runtime known name,
  something like .data[name], you skip the prefix layer anyway, so it
  won't interfere.

- If some of parts of the template is auto-generated, then you can
  still chose to store the prefix in a plain template-defined/local
  variable, which in my language can't hide the data-model, because
  (now prepare for shock) you must use a @ prefix before their names.
  (This last decision surely demands explanation, but it's OT now. OK,
  one factor is that since you are not supposed to do calculations in
  a template, you are assumed to use non-data-model variables
  relatively seldom. Anyway, PHP and Velocity survives with demanding
  you to put $ before *all* variables for, well, not very convicting
  reasons... yet people are not pulling their hair out, so I suppose
  most people don't mind typing odd symbols before variable names. I
  do, but... well, at least in this case I get something in exchange:
  looking at @foo immediately tells me that "foo" is not something
  from that undeclared sea of variables that are in the data-model,
  and foo immediately tells me it is from the data-model... or, it's a
  prefix. /-: )

- Prefixes are usually short, like "m" "fw", etc., while data-model
  variables aren't usually.

> I can envision a scenario where such a collision would be hard to
> detect (in that no error would be thrown): both the model object
> named x and a namespace imported as x have a same "method
> signature".
>
>> > I agree to a certain extent, but to me it really depends on the
>> > situation. For ex, when I'm programming in Java, I try to be a strict as
>> > possible to take advantage of the static checking, but when I'm using
>> > Python, I just generally follow best practices and rely on unit tests.
>> > FreeMarker is somewhere between the two - dynamic yet trying to be
>> > rigid. As I noted, the spectrum between "dynamic" and "static" is wide
>> > and there are plenty of advantages and disadvantages on each extreme. So
>> > exactly what you pick is a matter of philosophical preference. And I
>> > personally lean toward "configurable dynamic-ness" where the language
>> > can be as dynamic or as rigid as the user wants.
>>
>> Surely that *sounds* like the ideal solution... but I'm not sure yet
>> if in practice how that will work out. Even a little option to be
>> un-strict can make things that worked reliably earlier become suddenly
>> complex and unreliable (because something that doesn't work only in 1%
>> of cases is immediately not reliable). I would rather think the way
>> out is remaining strict, but with more powerful type system and like
>> (see Scala), but we shall see...
>>  
>
> So you want extensibility, but "strict" extensibility. I like the idea,
> but again it really depends on the situation and what exactly is
> extensible, e.g. if you're designing a template engine that targets
> arbitrary template languages, you do want a lot of flexibility, but
> within a particular language, not so much. Also note that even the
> notoriously strict Java can be fairly dynamic with reflection [abuse].

I surely don't want to design an engine that targets arbitrary
template languages, because template languages can be fundamentally
different, which would led to more and more layers of abstraction,
that would make the stuff damn hard to understand and use for mere
mortals. I want to target a specific class of template engines, which
I could describe as WebMacro/Velocty/FreeMarker and it's ad-hoc gown
pals. That concept I want to extend on a few ways (like on the field
of ensuring valid output), but it's still that good-old imperative
stuff. There are the other kind of template languages, like ZPT, or
Wicket's templates, etc. I don't say they are mistaken or anything,
but I just don't want to target that field, because its requirements
are too different. So what I want to achieve with customization: I
want to save people from inventing their own little-lame ad-hoc
WebMacro-like template engines here and there, because none of the
available ones had the ideal syntax (e.g., when the template syntax
clashes with something that is frequent in your static parts...), many
of them had a too intrusive language (in a mail client you want CC to
be a *core* directive, no stupid prefixes...), had too intrusive API
(e.g., your storage logic is not like getting templates by path-like
strings), etc. I know I can't satisfy all such cases, but being a bit
smarter I'm sure I can save a few times more than FM can.

Also, I think we have to understand that dynamic Web pages become less
and less important for this kind of template language... FM was
basically about that, generating HTML pages in Web MVC, but was
universal enough to be usable elsewhere. Component-oriented Web UI-s
should slowly kill that filed now, so the alternative use-case become
more important, and those are much more diverse, so you can do less
assumptions than before. So that's again something why I want to allow
the easy creation of custom languages. Easy means that you can build
it merely by configuring stuff.

>> > IDE support isn't a big issue IMO. To me, there are 2 main things
>> > the IDEs can provide: 1) refactoring/boilerplate aid, and 2) syntax
>> > highlighting/visual assist.
>>
>> Good for you! For me, marking the typos (like in method names) and
>> auto-completion (especially for parameter lists) is a must-have too. I
>> just don't have the mental ability of typing without error and
>> memorizing tons of API-s to the letter... But I think I'm not
>> completely alone with these.
>>  
>
> Yet dynamic languages that lack extensive IDE support still flourish. To
> each, his own.

But it's not like people chose tools on their *inherent* technical
merits. Like, as an example, PHP is still the most widespread language
for creating web stuff, and certainly 20 years later it still will
be... Why? I guess because back then it was on the right place on the
right time, so it grew a huge user-base. And since it's what everyone
uses, it's what everyone tries, and stuck with. Anyway, because of the
huge user-base and focused goal (Web...) there is are tons of useful
3rd party libraries for you. Also, you barely can find a Web server
where PHP isn't installed, which makes life easy. So now actually you
have good technical reasons to choose it. So PHP is raging success,
but not at all because it's a so bright concept or anything... it's
not that at all.

> Regards, Yuh-Ruey

--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Attila Szegedi-3

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
In reply to this post by Yuh-Ruey Chen
Folks, reading all this, I keep thinking "Lisp" more and more.  
Selectively walkable AST, configurable overriding rules, scoped let  
directive, newly defined directives being same level citizens as  
previously defined ones, etc. etc.

Lots of things you discuss are very close to invoking Greenspun's  
Tenth Rule, so you might as well go the full length and embrace Lisp  
for a template engine project. I can quite warmheartedly suggest  
Clojure - it's a Lisp, and it's native to JVM, and it's modern,  
performant, and concurrency-safe, among other things. It also compiles  
to Java bytecode. I think I'm actually getting excited at the prospect  
of creating a template engine in Clojure. Or it might actually be  
*the* template engine in Clojure, because if some basics with default  
behaviour are laid, down, anyone can go in there and customize  
anything on any level with an appropriate new set of Lisp macros.

Just a brainstorming idea...

Attila.

On 2009.09.17., at 1:42, Yuh-Ruey Chen wrote:

> Daniel Dekany wrote:
>> Wednesday, September 16, 2009, 12:21:47 PM, Yuh-Ruey Chen wrote:
>>
>>> Daniel Dekany wrote:
>>> Yes, there are a couple directives that take effect before the
>>> evaluation of the template. #ftl configures the template. #noparse,
>>> #compress, #t, #lt, #rt, and #nt affect parsing. Maybe these  
>>> directives
>>> should have a slightly different syntax to denote this difference,  
>>> e.g.
>>> [#ftl#] or [#t#] (similar to <?xml-processing-instruction?>).
>>
>> Been there... I ended up on the standpoint that it doesn't worth it
>> (unless you have tons of fancy "pre-processor" directives and like in
>> which case it becomes crucial to visually separate what is executed  
>> in
>> the 1st, and what in the 2nd phase). It adds visual clutter, and is
>> one more thing to remember for most users... you language looks more
>> complex, more confusing. All that for a little theoretical clarity,
>> doesn't worth it.
>>
>
> Fair enough. I also don't think it's worth it, and it's unlikely that
> there will be many new "parsing directives".
>
>>> But I'm not aware of any builtin functions that have such effects.
>>
>> Not that it's impossible that one day you want to add a such
>> function...
>>
>
> Can you give an example of an operation affecting parsing that would  
> be
> better of as a function (within an expression that's evaluated at
> runtime!) than as a directive?
>
>>>>> Adding functions to the data model (or shared vars) always feels  
>>>>> a bit
>>>>> clunky to me, because it does collide with the rest of the data  
>>>>> model.
>>>>
>>>> Yes. But later ?new and #import was introduced to counter that
>>>> tradition.
>>>
>>> I'm just not sure if functions should even belong in the data  
>>> model at
>>> all. I'd rather they be in their own "namespace"
>>
>> Exactly... Java Language has the trick for it (methods VS fields),  
>> and
>> I applied exactly the same trick: if you call it, the name is to be
>> searched in the method namespace, otherwise in the plain-variable
>> namespace. It makes getting methods as values a bit tricky (yet
>> possible: currying), but in exchange you get a lot of benefits. And
>> the same trick you can apply on the data-model, so Map items doesn't
>> conflict with Map methods anymore.
>>
>
> Well that's an odd use of currying. In any case, I don't know what the
> future holds for Java's popularity, but the JVM will likely stick  
> around
> for a while, so it may not be such a good idea to tie a template
> language so closely to Java's quirks. For example, you mention Scala
> (which is a language I'm very interested in delving into), and it has
> function objects.
>
>> Now, at this point, let me ask, why are you so interested in template
>> language design? I mean, it looks like you have given considerable
>> amount of thought to the topic. So, what are you up to?
>>
>
> Taking over the world of course.
>
> Seriously, I just have a general interest in programming language
> design. And I haven't spent that much time thinking about template
> languages in particular - maybe less than half a day's worth with  
> these
> emails.
>
> And now a question of my own: do you ever intend to act on any of  
> these
> language redesigns? :)
>
>>> Also, we could just get rid of "using" in #visit and #recurse,  
>>> treating
>>> "namespace" is an optional param:
>>>
>>> [#recurse doc]
>>> [#recurse doc, namespace]
>>
>> This kind of usage of keywords it actually the result of not using
>> named parameters. I mean, [#recurse doc, namespace] is not very
>> telling, [#recurse doc using namespace] is. But, using named
>> parameters, [#recurse doc, using: namespace] would be too...
>>
>
> But what makes [#recurse] or [#visit] so special that it deserves the
> same "syntactic attention" as assignment or conditionals? #recurse and
> #visit could just be left out of the core and defined in a library (in
> Java of course).
>
> To give some perspective: I defined a directive called #let that I use
> to create "scopes":
>
> [@let expr; var]
>   usage of ${var}
> [/@let]
>
> which is a "shortcut" for
>
> [#macro some_name_just_provides_scoping]
>   [#set var = expr]
>   usage of ${var}
> [/#macro]
> [@some_name_just_provides_scoping]
>
> It seems "unfair" that [#recurse] or [#visit] get special attention,
> when this particular user-defined directive is more "core-like".
>
>>> That leaves #if/#else/#elseif, and #switch/#case/#default as the  
>>> only
>>> directives that require special parsing (besides the ones the affect
>>> parsing itself, noted above).
>>
>> They are not *that* special necessarily. In FTL only #if had an
>> end-tag, not the #else/#leseif, which makes then quite much special.
>> But that can be avoided with a different syntax. Like, in
>> WebMacro-style (which is basically JavaScript-style) there is no such
>> kind of problem whatsoever. The only speciality that remains is the
>> way how if/else/elseif changes the control flow. Like, a successful
>> #if skips all following #else/#elseif *siblings*. It's a bit extreme
>> that node has such control over his siblings (as opposed to over its
>> children).
>>
>
> One point that I forgot to mention is how builtin directives could  
> omit
> the "/" for body-less directives (in fact, I'm not even sure it's
> legal?). Which makes #else (among others) special.
>
> Here's a wild suggestion concerning control flow: Add a method to
> DirectiveBody that returns a new template (essentially uses the same
> context as the current template and is rooted at the directive  
> template
> element). Then the user can walk the AST and selectively execute  
> nodes.
> That would allow advanced FreeMarker users (from the Java side) to
> implement nearly any non-parsing directive they want.
>
>>> Also, it can be incompatible with other JVM languages that
>>> allow class-less functions to be defined, tying FreeMarker too  
>>> closely
>>> with Java.
>>>
>>> On a related note, I think it would be better to not treat FM  
>>> namespaces
>>> like any other hash, making it look like it's part of the data  
>>> model.
>>
>> Yeah... but unfortunately, that has it's drawbacks to. Like, since
>> namespace *are* hashes, you may want to pass them around as values.
>> How do you refer to them then? "ns:.root" or something... awkward.  
>> But
>> whatever... However funny is, the bigger problem I ran into is that
>> there is pretty big competition for the ":" symbol. Named parameters
>> want that, ternary operator want that... and if more of them has it,
>> you usually end up with an ambiguous syntax. So, surely in general
>> it's desirable to separate namespace prefixes from other variables,
>> but unfortunately at the end of that circle (referring to the  
>> "running
>> circles" I wrote about earlier) you may end up without that.
>>
>
> True. Using ":" may also be result in some confusion with XML
> namespaces, e.g. ${node["x:foo"]} vs . ${node[x:foo]}.
>
> But still, namespaces colliding with the data model is bad. I can
> envision a scenario where such a collision would be hard to detect (in
> that no error would be thrown): both the model object named x and a
> namespace imported as x have a same "method signature".
>
>>> I agree to a certain extent, but to me it really depends on the
>>> situation. For ex, when I'm programming in Java, I try to be a  
>>> strict as
>>> possible to take advantage of the static checking, but when I'm  
>>> using
>>> Python, I just generally follow best practices and rely on unit  
>>> tests.
>>> FreeMarker is somewhere between the two - dynamic yet trying to be
>>> rigid. As I noted, the spectrum between "dynamic" and "static" is  
>>> wide
>>> and there are plenty of advantages and disadvantages on each  
>>> extreme. So
>>> exactly what you pick is a matter of philosophical preference. And I
>>> personally lean toward "configurable dynamic-ness" where the  
>>> language
>>> can be as dynamic or as rigid as the user wants.
>>
>> Surely that *sounds* like the ideal solution... but I'm not sure yet
>> if in practice how that will work out. Even a little option to be
>> un-strict can make things that worked reliably earlier become  
>> suddenly
>> complex and unreliable (because something that doesn't work only in  
>> 1%
>> of cases is immediately not reliable). I would rather think the way
>> out is remaining strict, but with more powerful type system and like
>> (see Scala), but we shall see...
>>
>
> So you want extensibility, but "strict" extensibility. I like the  
> idea,
> but again it really depends on the situation and what exactly is
> extensible, e.g. if you're designing a template engine that targets
> arbitrary template languages, you do want a lot of flexibility, but
> within a particular language, not so much. Also note that even the
> notoriously strict Java can be fairly dynamic with reflection [abuse].
>
>>> IDE support isn't a big issue IMO. To me, there are 2 main things
>>> the IDEs can provide: 1) refactoring/boilerplate aid, and 2) syntax
>>> highlighting/visual assist.
>>
>> Good for you! For me, marking the typos (like in method names) and
>> auto-completion (especially for parameter lists) is a must-have  
>> too. I
>> just don't have the mental ability of typing without error and
>> memorizing tons of API-s to the letter... But I think I'm not
>> completely alone with these.
>>
>
> Yet dynamic languages that lack extensive IDE support still  
> flourish. To
> each, his own.
>
> Regards, Yuh-Ruey

Attila.

--
twitter: http://twitter.com/szegedi
weblog: http://constc.blogspot.com






------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Attila Szegedi-3

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
In reply to this post by Daniel Dekany
On 2009.09.15., at 6:27, Daniel Dekany wrote:

> (Configurable language rules... I would allow it only if you define a
> new template language... that could/should be made easy, but still,
> you have to give it another name.)

I suggest "Lisp". No, seriously, for a practical Java solution, just  
take Clojure, add some reader macros that allow you nice expression of  
templates, and then you can configure everything else you want using  
other macros.

Attila.


------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Daniel Dekany

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Monday, September 21, 2009, 10:38:31 AM, Attila Szegedi wrote:

> On 2009.09.15., at 6:27, Daniel Dekany wrote:
>
>> (Configurable language rules... I would allow it only if you define a
>> new template language... that could/should be made easy, but still,
>> you have to give it another name.)
>
> I suggest "Lisp". No, seriously, for a practical Java solution, just  
> take Clojure, add some reader macros that allow you nice expression of
> templates, and then you can configure everything else you want using  
> other macros.

You think that way you end up with a solution that can be distributed
as an easy-to-use and reasonably light-weight template engine? One
that has an API and syntax that you imagined?

> Attila.

--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Attila Szegedi-3

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
On 2009.09.21., at 22:48, Daniel Dekany wrote:

> Monday, September 21, 2009, 10:38:31 AM, Attila Szegedi wrote:
>
>> On 2009.09.15., at 6:27, Daniel Dekany wrote:
>>
>>> (Configurable language rules... I would allow it only if you  
>>> define a
>>> new template language... that could/should be made easy, but still,
>>> you have to give it another name.)
>>
>> I suggest "Lisp". No, seriously, for a practical Java solution, just
>> take Clojure, add some reader macros that allow you nice expression  
>> of
>> templates, and then you can configure everything else you want using
>> other macros.
>
> You think that way you end up with a solution that can be distributed
> as an easy-to-use and reasonably light-weight template engine? One
> that has an API and syntax that you imagined?

I believe yes. I can't prove it otherwise than actually attempting to  
do it, though.

Attila.

>> Attila.
>
> --
> Best regards,
> Daniel Dekany

------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Daniel Dekany

Re: FreeMarker issues (was FreeMarker XML issues)

Reply Threaded More More options
Print post
Permalink
Tuesday, September 22, 2009, 1:23:58 AM, Attila Szegedi wrote:

> On 2009.09.21., at 22:48, Daniel Dekany wrote:
>
>> Monday, September 21, 2009, 10:38:31 AM, Attila Szegedi wrote:
>>
>>> On 2009.09.15., at 6:27, Daniel Dekany wrote:
>>>
>>>> (Configurable language rules... I would allow it only if you  
>>>> define a
>>>> new template language... that could/should be made easy, but still,
>>>> you have to give it another name.)
>>>
>>> I suggest "Lisp". No, seriously, for a practical Java solution, just
>>> take Clojure, add some reader macros that allow you nice expression  
>>> of
>>> templates, and then you can configure everything else you want using
>>> other macros.
>>
>> You think that way you end up with a solution that can be distributed
>> as an easy-to-use and reasonably light-weight template engine? One
>> that has an API and syntax that you imagined?
>
> I believe yes. I can't prove it otherwise than actually attempting to
> do it, though.

To make it clear, it's OK for me if I can use Clojure as an
implementation of the template language, but I certainly wouldn't
tolerate if Clojure dictates the language design too much... (And I
bet it spoils the error messages.)

BTW, when I considered how to do the multiple-bodies thing (a frequent
request) I found that, of course, for doing that in a nice/generic way
(means, parameters and bodies are the same thing) you should switch to
functional programming. That's because the order of the execution of
the "blocks" can be quite different from what you would deduce from
looking at the source code, and that's confusing if you have mutable
variables. But surely you don't want functional programming in a
practical template language that targets average IT guys, do you?

--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel