You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by "Daniel Dekany (JIRA)" <ji...@apache.org> on 2017/07/11 18:29:00 UTC

[jira] [Commented] (FREEMARKER-61) ?sort_using with a Comparator parameter

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

Daniel Dekany commented on FREEMARKER-61:
-----------------------------------------

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)