freemarker-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Daniel Dekany (JIRA)" <j...@apache.org>
Subject [jira] [Comment Edited] (FREEMARKER-61) ?sort_using with a Comparator parameter
Date Tue, 11 Jul 2017 18:34:00 GMT

    [ https://issues.apache.org/jira/browse/FREEMARKER-61?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16082709#comment-16082709
] 

Daniel Dekany edited comment on FREEMARKER-61 at 7/11/17 6:33 PM:
------------------------------------------------------------------

Just to be sure that we are on the same page, I will tell that you could just put a Java method
like {{List sort(List, Comparator)}} into the data-model or into {{configuration.sharedVariables}},
and you are done. As with {{?sort_using}} you still need to add the {{Comparator}}-s, {{?sort_using}}
is not a too big help. Though then there are the guys who can't add Java classes, and for
them using {{?sort_using}} with {{#function}} can be very handy... except that such cases
are quite serious misuses of poor FreeMarker (it never meant to be a programming language,
and indeed it's very, very poor as that), and by supporting such things, we might encourage
people to do these things even more. Only to run into performance issues later...

Anyway, if we want this, then I think {{?sort_using}} should accept a parameter that is either
a {{Comparator}} (and then we have to unwrap the model to see), or an FTL method/function
(which behaves like {{Comparator.compare}}). So someone could even create a {{#function}}
for sorting, at least if performance doesn't mater. When you use it, it would be like {{myData.persons?sort_using(sortByName)}},
where {{sortByName}} is just plain old variable reference, but you could use any other expression
there of course (like {{myImport.myComparator}}). There are no quotation marks, as it's not
a string.

There are some performance issues though, even if you are using Java {{Comparator}}-s. FTL
deals with wrapped objects ({{TemplateModel}}-s). If you invoke the wrapped {{Comparator.compare}}
method, or any wrapped Java method (as opposed to something defined with {{#function}}), then
behind the scenes it will unwrap the argument models to "native" Java objects, pass those
the native Java method, then wrap the return value back to FTL {{TemplateNumberModel}}-s.
Worse, the typical {{List}} wrapper will wrap the item on the spot when you get them, so it
only wraps them so that it can be unwrapped moments later... It still works, but because you
will invoke the comparator for several times, often with the same arguments, the overhead
of all that unwrapping/wrapping might be significant. If instead, we unwrap the {{List}} itself
and then sort it, you only unwrap the {{List}}, not each items in it, which is much better.
I wonder though if we deviate from FTL semantic that way in some extreme cases... not sure
yet. And you still have to deal with the values that aren't wrapped {{List}}-s, but are still
FTL sequences.


was (Author: ddekany):
Just to be sure that we are on the same page, I will tell that you could just put a Java method
like {{List sort(List, Comparator)}} into the data-model or into {{configuration.sharedVariables}},
and you are done. As with {{?sort_using}} you still need to add the {{Comparator}}-s, {{?sort_using}}
is not a too big help. Though then there are the guys who can't add Java classes, and for
them using {{?sort_using}} with {{#function}} can be very handy... except that such cases
are quite serious misuses of poor FreeMarker (it never meant to be a programming language,
and indeed it's very, very poor as that), and by supporting such things, we might encourage
people to do these things even more. Only to run into performance issues later...

Anyway, if we want this, then I think {{?sort_using}} should accept a parameter that is either
a {{Comparator}} (and then we have to unwrap the model to see), or an FTL method/function
(which behaves like `Comparator.compare`). So someone could even create a `#function` for
sorting, at least if performance doesn't mater. When you use it, it would be like {{myData.persons?sort_using(sortByName)}},
where {{sortByName}} is just plain old variable reference, but you could use any other expression
there of course (like {{myImport.myComparator}]). There are no quotation marks, as it's not
a string.

There are some performance issues though, even if you are using Java {{Comparator}}-s. FTL
deals with wrapped objects ({{TemplateModel}}-s). If you invoke the wrapped {{Comparator.compare}}
method, or any wrapped Java method (as opposed to something defined with {{#function}}), then
behind the scenes it will unwrap the argument models to "native" Java objects, pass those
the native Java method, then wrap the return value back to FTL {{TemplateNumberModel}}-s.
Worse, the typical {{List}} wrapper will wrap the item on the spot when you get them, so it
only wraps them so that it can be unwrapped moments later... It still works, but because you
will invoke the comparator for several times, often with the same arguments, the overhead
of all that unwrapping/wrapping might be significant. If instead, we unwrap the {{List<Person>}}
itself and then sort it, you only unwrap the {{List}}, not each items in it, which is much
better. I wonder though if we deviate from FTL semantic that way in some extreme cases...
not sure yet.

> ?sort_using with a Comparator parameter
> ---------------------------------------
>
>                 Key: FREEMARKER-61
>                 URL: https://issues.apache.org/jira/browse/FREEMARKER-61
>             Project: Apache Freemarker
>          Issue Type: New Feature
>          Components: engine
>    Affects Versions: 2.3.26-incubating
>            Reporter: Ondra Žižka
>
> Hi Daniel :)
> I know that lists should be sorted before passing them to the template in general.
> In our case, the template is backed by a generic API for graph database which gives an
{{Iterable}} for any 1:N relation. So sorting needs to happen in the template.
> Now I'd like to sort that, for which the {{?sort_by(["...", "..."])}} is good enough,
except when it gets a bit more complicated - e.g. sometimes the values are missing in which
case it should sort by something else...
> Doing that in a template is not a good idea, so I suggest this, elegant in my opinion,
solution:
> First you'd have a Comparator in Java, and perhaps register it like you do with {{FreemarkerMethod}}.
> Then you could pass this as a parameter to {{?sort_using.}}
> {code}
> public class SortByName implements Comparator { ... }
> myData.persons?sort_using("SortByName")
> {code}
> This would be even better if it could pass parameters to the constructor:
> {code}
> public class SortByName implements Comparator {
>     public SortByName(boolean ladiesFirst) { ... }
> }
> myData.persons?sort_using("SortByName", [true])
> {code}
> This would greatly leverage sorting in templates while not complicating the template
syntax or cluttering {{?sort_by}}.
> Thanks for considering.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

Mime
View raw message