Re: [FM3] Call syntax, positional and named parameters

2017-07-05 Thread Daniel Dekany
Something from the first mail of this thread that I want to emphasize
is that which parameter needs to be passed by position and which by
name is decided when the directive or function is defined. It's not
decided by the caller (see reasons below).

For example, the 1st parameter of #include can only be passed by
position, as in `<#include "foo.ftl">`. You can't write
`<#include template="foo.ftl">`. However, the `ignoreMissing`
parameter (and in FM2 we also had `encoding` and `parse` parameters)
can only be passed by name, as in
`<#include "foo.ftl" ignoreMissing=true>`. You can't write
`<#include "foo.ftl", true>`.

Some may have used languages where the caller decides what is passed
by position and what by name, but IMO it just leads to chaos in our
case. I also realize and accept that everybody has different taste,
but people read/edit other people's code a lot, so the taste of the
original author often doesn't matter much. Plus if someone overuses
positional parameters (laziness/rushing and C/Java habits may make
people do that...), the template becomes less readable, especially for
someone less experienced with writing templates. Consistency regarding
how core directives are called is even more valuable, as people
copy-paste it from StackOverflow etc. Imagine if in some cases you see
`<#if test=foo>`, while in others <#if foo>... confusing or annoying.

Now, we don't yet have a syntax in #macro and #function calls to
declare if a parameter passed by positional or by named. How should it
look?

My idea is that for directives by-name will be the default, and for
functions by-positional will be the default. To deviate from the
defaults, you add the proper option after the parameter name inside
`{}`, where `{}` is also a new thing, which will be later useful for
specifying other parameter related options as well (like, with a
totally fictional example, `myParam{byName, allowNull, max=100}`).

So here `x` and `y` are passed by position, and `color` and `id` by
name (and `id` defaults to `null`):

  <#macro message text{byPosition}, color id=null>...
  <#function message(text, color{byName}, id{byName}=null)>...

So you can call these as:

  <@message 'Hello World' color='red' id='test' />

and

  message('Hello World', color='red', id='test')



Wednesday, July 5, 2017, 5:19:56 PM, Woonsan Ko wrote:

> On Tue, Jul 4, 2017 at 10:15 AM, Daniel Dekany  wrote:
>> Tuesday, July 4, 2017, 7:57:18 AM, Woonsan Ko wrote:
>>
>>> On Wed, Jun 21, 2017 at 2:30 PM, Daniel Dekany  wrote:
 Friday, June 16, 2017, 8:41:37 PM, Daniel Dekany wrote:

> A problem in FM2 is that when calling a directive (as a macro), either
> all parameters are positional (`<@message "Hi" 2 />`), or all
> parameters are named (`<@message content="Hi" height=2 />`); you can't
> mix the two (`<@message "Hi" height=2 />`). Also you can't use named
> parameters for functions/methods, only for directives. Worse, core
> directives don't even use named parameters, but some keyword like
> `as`, `using`... their syntax is hard coded into the parser, which is
> not nice, and will be a problem for the custom dialects feature.
>
> I think that with the exception of a few core directives (see them
> later) all directive calls should be like this, if for now (in this
> thread) we ignore loop variables:
>
>   <#name posPar1 posPar2 namedPar1Name=namedPar1Value 
> namedPar2=namedPar2Value>

 An adjustment to the above... I think that we should require comma
 between positional arguments (but not between positional and named
 arguments and between named arguments):
>>>
>>> "but not between ..." means that a comma can be *optionally* placed
>>> between named arguments or between a positioned argument and a named
>>> argument, right?
>>
>> I wouldn't allow that. If we do, then where to put comma becomes a
>> matter of taste, and the taste of individuals in the same project
>> differ, or for OS projects, whoever bumps into the templates might has
>> a different taste. So overall, you just end up with chaos, and if some
>> cares much, it's just unnecessary struggle (which of the 3
>> combinations is the Right Way). So I believe it's better overall if we
>> decide what's the right way for everyone... Especially as our taste is
>> based on more knowledge. FTL tags have this HTML-ish look-and-feel, so
>> naturally you write `<#foo n1=v1 n2=v2 m3=v3>`, and not
>> `<#foo n1=v1, n2=v2, m3=v3>`. So now, if we add a single positional
>> parameter, I think most will find it consistent like this:
>> `<#foo v0 n1=v1 n2=v2 m3=v3>` (like in `<@message "Hi" height=2 />`).
>> Still no comas anywhere. In the hopefully rare case when you have
>> multiple positional parameters, we unfortunately ran into ambiguity
>> issues, so then, and only then, and only between the positional
>> parameters you add commas. I think that's also matches common
>> conventions, 

Re: [FM3] Call syntax, positional and named parameters

2017-07-05 Thread Woonsan Ko
On Tue, Jul 4, 2017 at 10:15 AM, Daniel Dekany  wrote:
> Tuesday, July 4, 2017, 7:57:18 AM, Woonsan Ko wrote:
>
>> On Wed, Jun 21, 2017 at 2:30 PM, Daniel Dekany  wrote:
>>> Friday, June 16, 2017, 8:41:37 PM, Daniel Dekany wrote:
>>>
 A problem in FM2 is that when calling a directive (as a macro), either
 all parameters are positional (`<@message "Hi" 2 />`), or all
 parameters are named (`<@message content="Hi" height=2 />`); you can't
 mix the two (`<@message "Hi" height=2 />`). Also you can't use named
 parameters for functions/methods, only for directives. Worse, core
 directives don't even use named parameters, but some keyword like
 `as`, `using`... their syntax is hard coded into the parser, which is
 not nice, and will be a problem for the custom dialects feature.

 I think that with the exception of a few core directives (see them
 later) all directive calls should be like this, if for now (in this
 thread) we ignore loop variables:

   <#name posPar1 posPar2 namedPar1Name=namedPar1Value 
 namedPar2=namedPar2Value>
>>>
>>> An adjustment to the above... I think that we should require comma
>>> between positional arguments (but not between positional and named
>>> arguments and between named arguments):
>>
>> "but not between ..." means that a comma can be *optionally* placed
>> between named arguments or between a positioned argument and a named
>> argument, right?
>
> I wouldn't allow that. If we do, then where to put comma becomes a
> matter of taste, and the taste of individuals in the same project
> differ, or for OS projects, whoever bumps into the templates might has
> a different taste. So overall, you just end up with chaos, and if some
> cares much, it's just unnecessary struggle (which of the 3
> combinations is the Right Way). So I believe it's better overall if we
> decide what's the right way for everyone... Especially as our taste is
> based on more knowledge. FTL tags have this HTML-ish look-and-feel, so
> naturally you write `<#foo n1=v1 n2=v2 m3=v3>`, and not
> `<#foo n1=v1, n2=v2, m3=v3>`. So now, if we add a single positional
> parameter, I think most will find it consistent like this:
> `<#foo v0 n1=v1 n2=v2 m3=v3>` (like in `<@message "Hi" height=2 />`).
> Still no comas anywhere. In the hopefully rare case when you have
> multiple positional parameters, we unfortunately ran into ambiguity
> issues, so then, and only then, and only between the positional
> parameters you add commas. I think that's also matches common
> conventions, where if you list something, you put commas *between* the
> listed items, but not after the last one. Named parameters aren't
> really listed (their order doesn't mater). So it's more logical to
> only use comma where you must, not just a matter of taste.

I concur with you now! Indeed, listing (positional args) requires
comma delimiter, but non-listing (named args) doesn't.

>
> BTW, I was never a fan of this HTML-ish look-and-feel, because of the
> confusing differences; people keep writing `foo="${x}"` instead of
> `foo=x`. But that's the FM tradition, so I try to remain consistent
> with the original idea. (When we manage to separate the expression
> syntax from the top-level syntax, I think I will try to introduce an
> officially supported alternative, something like `#foo(v0, n1=v1,
> n2=v2, m3=v3)`.)

That sounds great, too!

Thanks again for the thorough thoughts and clarifications!

Cheers,

Woonsan

>
>> In other words, it is allowed to omit a comma between positional arg
>> and named arg or between named args.
>>
>> Woonsan
>>
>>>
>>>   <#name posPar1, posPar2 namedPar1Name=namedPar1Value 
>>> namedPar2=namedPar2Value>
>>
>
> --
> Thanks,
>  Daniel Dekany
>


Re: [FM3] Call syntax, positional and named parameters

2017-07-04 Thread Daniel Dekany
Tuesday, July 4, 2017, 7:57:18 AM, Woonsan Ko wrote:

> On Wed, Jun 21, 2017 at 2:30 PM, Daniel Dekany  wrote:
>> Friday, June 16, 2017, 8:41:37 PM, Daniel Dekany wrote:
>>
>>> A problem in FM2 is that when calling a directive (as a macro), either
>>> all parameters are positional (`<@message "Hi" 2 />`), or all
>>> parameters are named (`<@message content="Hi" height=2 />`); you can't
>>> mix the two (`<@message "Hi" height=2 />`). Also you can't use named
>>> parameters for functions/methods, only for directives. Worse, core
>>> directives don't even use named parameters, but some keyword like
>>> `as`, `using`... their syntax is hard coded into the parser, which is
>>> not nice, and will be a problem for the custom dialects feature.
>>>
>>> I think that with the exception of a few core directives (see them
>>> later) all directive calls should be like this, if for now (in this
>>> thread) we ignore loop variables:
>>>
>>>   <#name posPar1 posPar2 namedPar1Name=namedPar1Value 
>>> namedPar2=namedPar2Value>
>>
>> An adjustment to the above... I think that we should require comma
>> between positional arguments (but not between positional and named
>> arguments and between named arguments):
>
> "but not between ..." means that a comma can be *optionally* placed
> between named arguments or between a positioned argument and a named
> argument, right?

I wouldn't allow that. If we do, then where to put comma becomes a
matter of taste, and the taste of individuals in the same project
differ, or for OS projects, whoever bumps into the templates might has
a different taste. So overall, you just end up with chaos, and if some
cares much, it's just unnecessary struggle (which of the 3
combinations is the Right Way). So I believe it's better overall if we
decide what's the right way for everyone... Especially as our taste is
based on more knowledge. FTL tags have this HTML-ish look-and-feel, so
naturally you write `<#foo n1=v1 n2=v2 m3=v3>`, and not
`<#foo n1=v1, n2=v2, m3=v3>`. So now, if we add a single positional
parameter, I think most will find it consistent like this:
`<#foo v0 n1=v1 n2=v2 m3=v3>` (like in `<@message "Hi" height=2 />`).
Still no comas anywhere. In the hopefully rare case when you have
multiple positional parameters, we unfortunately ran into ambiguity
issues, so then, and only then, and only between the positional
parameters you add commas. I think that's also matches common
conventions, where if you list something, you put commas *between* the
listed items, but not after the last one. Named parameters aren't
really listed (their order doesn't mater). So it's more logical to
only use comma where you must, not just a matter of taste.

BTW, I was never a fan of this HTML-ish look-and-feel, because of the
confusing differences; people keep writing `foo="${x}"` instead of
`foo=x`. But that's the FM tradition, so I try to remain consistent
with the original idea. (When we manage to separate the expression
syntax from the top-level syntax, I think I will try to introduce an
officially supported alternative, something like `#foo(v0, n1=v1,
n2=v2, m3=v3)`.)

> In other words, it is allowed to omit a comma between positional arg
> and named arg or between named args.
>
> Woonsan
>
>>
>>   <#name posPar1, posPar2 namedPar1Name=namedPar1Value 
>> namedPar2=namedPar2Value>
>

-- 
Thanks,
 Daniel Dekany



Re: [FM3] Call syntax, positional and named parameters

2017-07-04 Thread Daniel Dekany
Tuesday, July 4, 2017, 7:29:23 AM, Woonsan Ko wrote:

> On Fri, Jun 16, 2017 at 2:41 PM, Daniel Dekany  wrote:
>>8>8
>> Some very fundamental core directives still would have exceptional
>> syntax, such as:
>>
>> - Assignments (#var/#set as planned for FM3). They look as if they
>>   have named parameter syntax first, but in the future we might want to
>>   allow things like `<#set x[i] = 1>` or `<#set ns.var = 1>`.
>>
>> - #macro and #function: As in pretty much all languages, the syntax for
>>   defining callable things is not the same as the syntax for calling
>>   things.
>>
>> - `<#list xs as x>`... though maybe it's not exceptional. `x` is just
>>   a loop variable, and I haven't talked about the standardization of
>>   that in this thread. But in FM2 it's like `<@myDirective blah;
>>   loopVar1, loopVarN>`. But `<#list xs; x>` is IMO not very readable.
>>   Maybe we should just allow `as` in place of `;` for custom
>>   directives, optionally.
>
> How about <#list xs as="x">

Loop variables (i.e., variables local to the nested content, set by
the enclosing directive) is a commonly used thing in a FreeMarker
(mostly because that #list is commonly used, but note that custom
directives also can have loop variables). Thus, the syntax must make
it clear that you create a loop variable there. If it's just `as="x"`,
then you had to look up in the #list documentation what that does.
More importantly, then tools won't know it.

> or <#list xs>? The latter could make 'it' available implicitly.

`<#list xs>` in FM2 means that you have a nested `<#item as x>`.

As of supporting `it` on other ways, I was thinking about that back
then, but concluded that the loss in clarity doesn't worth it. The
smaller problem is that unless you have Groovy background, you will
have hard time realizing what's going on. The bigger problem is that
especially when you have a longer section nested inside the #list call
(and also when you have multiple #list-s nested into each other),
seeing things like `${it.name}` is much less talking than seeing
`${user.name}`. I'm certain that the majority of those users who know
about `it` would overuse it, making FreeMarker templates less readable
overall. If the user is enforced to give a name to the loop variable,
then it's much less likely that they will call it `i` or `it`.

>> Along with these, I would like to remove `=` as a comparator operator
>> (an alias to `==`). It was already a problem in FM2, as it leads to
>> ambiguities because `=` is also used for named parameters, but if we
>> allow the above things, then it's a much bigger problem.
>
> +1
>
>>
>> I also would like to allow using `-` unescaped in directive and
>> parameter names, like `<@my.foo-bar data-x=123 />` (This is a frequent
>> FM2 request, but couldn't be done because of `=`.)
>
> +0 (since I don't know why it has been requested and I usually don't
> use hyphen in names)

It's because of the HTML 5 `data-...` attributes, and because many XML
schemas use `-` in element and attribute names. We are affected by
those because of declarative XML processing (where you name the
handler macro after the element), and because of stuff like `<#macro m
p1, p2, pN, extraHtmlAttrs...>`, which some want to call like `<@m 1,
2, 3 style='foo' data-bar="baaz" />`. (It's not something I have made
up. It's a very frequent user request.)


> Regards,
>
> Woonsan
>
>>
>> --
>> Thanks,
>>  Daniel Dekany
>>
>

-- 
Thanks,
 Daniel Dekany



Re: [FM3] Call syntax, positional and named parameters

2017-07-03 Thread Woonsan Ko
On Wed, Jun 21, 2017 at 2:30 PM, Daniel Dekany  wrote:
> Friday, June 16, 2017, 8:41:37 PM, Daniel Dekany wrote:
>
>> A problem in FM2 is that when calling a directive (as a macro), either
>> all parameters are positional (`<@message "Hi" 2 />`), or all
>> parameters are named (`<@message content="Hi" height=2 />`); you can't
>> mix the two (`<@message "Hi" height=2 />`). Also you can't use named
>> parameters for functions/methods, only for directives. Worse, core
>> directives don't even use named parameters, but some keyword like
>> `as`, `using`... their syntax is hard coded into the parser, which is
>> not nice, and will be a problem for the custom dialects feature.
>>
>> I think that with the exception of a few core directives (see them
>> later) all directive calls should be like this, if for now (in this
>> thread) we ignore loop variables:
>>
>>   <#name posPar1 posPar2 namedPar1Name=namedPar1Value 
>> namedPar2=namedPar2Value>
>
> An adjustment to the above... I think that we should require comma
> between positional arguments (but not between positional and named
> arguments and between named arguments):

"but not between ..." means that a comma can be *optionally* placed
between named arguments or between a positioned argument and a named
argument, right?
In other words, it is allowed to omit a comma between positional arg
and named arg or between named args.

Woonsan

>
>   <#name posPar1, posPar2 namedPar1Name=namedPar1Value 
> namedPar2=namedPar2Value>


Re: [FM3] Call syntax, positional and named parameters

2017-07-03 Thread Woonsan Ko
On Wed, Jun 21, 2017 at 2:30 PM, Daniel Dekany  wrote:
> Friday, June 16, 2017, 8:41:37 PM, Daniel Dekany wrote:
>
>> A problem in FM2 is that when calling a directive (as a macro), either
>> all parameters are positional (`<@message "Hi" 2 />`), or all
>> parameters are named (`<@message content="Hi" height=2 />`); you can't
>> mix the two (`<@message "Hi" height=2 />`). Also you can't use named
>> parameters for functions/methods, only for directives. Worse, core
>> directives don't even use named parameters, but some keyword like
>> `as`, `using`... their syntax is hard coded into the parser, which is
>> not nice, and will be a problem for the custom dialects feature.
>>
>> I think that with the exception of a few core directives (see them
>> later) all directive calls should be like this, if for now (in this
>> thread) we ignore loop variables:
>>
>>   <#name posPar1 posPar2 namedPar1Name=namedPar1Value 
>> namedPar2=namedPar2Value>
>
> An adjustment to the above... I think that we should require comma
> between positional arguments (but not between positional and named
> arguments and between named arguments):
>
>   <#name posPar1, posPar2 namedPar1Name=namedPar1Value 
> namedPar2=namedPar2Value>

+1

>8>8
> For function calls, which follow typical C-ish expression syntax,
> using commas even between named parameters is the natural thing (as in
> `f(1, 2, foo=3, bar=4)`), so I would stick to that.

+1

>
> [snip]
>> parameters is `<#ftl outputFormat='RTF'>`. So far it's the same as in
>> FM2. But now we could have both in once call, such as
>> `<#visit node handlers=myNamespace>` (regular syntax), which was
>> `<#visit node using myNamespace>` in FM2 (irregular syntax hard coded
>> into the parser).
> [snip]
>
> For completeness, let's see what other non-regular core directives we
> have.
>
> - For #import I would switch to assignment-like approach:
>   FM2: <#import "foo.ftl" as f> <#import "bar.ftl" as b>
>   FM3: <#import f="foo.ftl" b="bar.ftl">

+1
Cool!

Cheers,

Woonsan

>
> - #escape doesn't mater, as it will be removed (in favor of output
>   formats introduced in 2.3.24).
>
> - #assign has this `in` thing, like `<#assign x = 1 in ns>`. We will
>   want to allow <#assign ns.x = 1> (actually, #set) anyway, so that
>   won't mater either.
>
> --
> Thanks,
>  Daniel Dekany
>


Re: [FM3] Call syntax, positional and named parameters

2017-07-03 Thread Woonsan Ko
On Fri, Jun 16, 2017 at 2:41 PM, Daniel Dekany  wrote:
>8>8
> Some very fundamental core directives still would have exceptional
> syntax, such as:
>
> - Assignments (#var/#set as planned for FM3). They look as if they
>   have named parameter syntax first, but in the future we might want to
>   allow things like `<#set x[i] = 1>` or `<#set ns.var = 1>`.
>
> - #macro and #function: As in pretty much all languages, the syntax for
>   defining callable things is not the same as the syntax for calling
>   things.
>
> - `<#list xs as x>`... though maybe it's not exceptional. `x` is just
>   a loop variable, and I haven't talked about the standardization of
>   that in this thread. But in FM2 it's like `<@myDirective blah;
>   loopVar1, loopVarN>`. But `<#list xs; x>` is IMO not very readable.
>   Maybe we should just allow `as` in place of `;` for custom
>   directives, optionally.

How about <#list xs as="x"> or <#list xs>? The latter could make 'it'
available implicitly.

>
> Along with these, I would like to remove `=` as a comparator operator
> (an alias to `==`). It was already a problem in FM2, as it leads to
> ambiguities because `=` is also used for named parameters, but if we
> allow the above things, then it's a much bigger problem.

+1

>
> I also would like to allow using `-` unescaped in directive and
> parameter names, like `<@my.foo-bar data-x=123 />` (This is a frequent
> FM2 request, but couldn't be done because of `=`.)

+0 (since I don't know why it has been requested and I usually don't
use hyphen in names)

Regards,

Woonsan

>
> --
> Thanks,
>  Daniel Dekany
>


Re: [FM3] Call syntax, positional and named parameters

2017-06-21 Thread Daniel Dekany
Friday, June 16, 2017, 8:41:37 PM, Daniel Dekany wrote:

> A problem in FM2 is that when calling a directive (as a macro), either
> all parameters are positional (`<@message "Hi" 2 />`), or all
> parameters are named (`<@message content="Hi" height=2 />`); you can't
> mix the two (`<@message "Hi" height=2 />`). Also you can't use named
> parameters for functions/methods, only for directives. Worse, core
> directives don't even use named parameters, but some keyword like
> `as`, `using`... their syntax is hard coded into the parser, which is
> not nice, and will be a problem for the custom dialects feature.
>
> I think that with the exception of a few core directives (see them
> later) all directive calls should be like this, if for now (in this
> thread) we ignore loop variables:
>
>   <#name posPar1 posPar2 namedPar1Name=namedPar1Value 
> namedPar2=namedPar2Value>

An adjustment to the above... I think that we should require comma
between positional arguments (but not between positional and named
arguments and between named arguments):

  <#name posPar1, posPar2 namedPar1Name=namedPar1Value namedPar2=namedPar2Value>

FM2 supports both the <@foo 1, 2, 3 /> and <@foo 1 2 3 /> variation
(and has no core directive with more the one positional argument,
hence I demonstrated it with a custom directive). I believe it's
better stick to one syntax or the other in FM3, not supporting both.
Question is, which one.

While <@foo 1 2 3 /> fits HTML style better, it can be ambiguous.
Consider:

- In `<@foo x - 1 />` is the argument `x - 1`, or we have an `x` and a `-1` 
argument?

- In `<@foo x! 1 />` is the argument `x!1`, or we have an `x!` and a `1` 
argument?

Technically, you can make whitespace significant, so that `<@foo x -1 />`
and `<@foo x - 1 />` has different meaning, but its a quite extreme
syntax design, and when you writing templates, I doubt many users will
even realize that such subtle rules exist. With comma, it's obvious to
do (`<@foo x - 1 />` VS `<@foo x, -1 />`, or even `<@foo x, - 1 />`). It
looks a bit odd next to named parameters, but certainly by far the
most common application of mixed positional and named parameters is
when you have only one positional parameters (<@launch rocket1 delay=3 />),
in which case the comma doesn't appear anyway.

For function calls, which follow typical C-ish expression syntax,
using commas even between named parameters is the natural thing (as in
`f(1, 2, foo=3, bar=4)`), so I would stick to that.

[snip]
> parameters is `<#ftl outputFormat='RTF'>`. So far it's the same as in
> FM2. But now we could have both in once call, such as
> `<#visit node handlers=myNamespace>` (regular syntax), which was
> `<#visit node using myNamespace>` in FM2 (irregular syntax hard coded
> into the parser).
[snip]

For completeness, let's see what other non-regular core directives we
have.

- For #import I would switch to assignment-like approach:
  FM2: <#import "foo.ftl" as f> <#import "bar.ftl" as b>
  FM3: <#import f="foo.ftl" b="bar.ftl">

- #escape doesn't mater, as it will be removed (in favor of output
  formats introduced in 2.3.24).

- #assign has this `in` thing, like `<#assign x = 1 in ns>`. We will
  want to allow <#assign ns.x = 1> (actually, #set) anyway, so that
  won't mater either.

-- 
Thanks,
 Daniel Dekany