freemarker-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Daniel Dekany <>
Subject Re: Lambda Expressions - filter list without <#list> directive
Date Sun, 31 Mar 2019 22:38:17 GMT
Monday, February 25, 2019, 10:19:25 AM, Christoph RĂ¼ger wrote:

>> > Overall those lambdas allow some great new use cases with pretty concise
>> > syntax. That is good. The ?filter and ?map built-ins are very cool
>> already.
>> > If some existing built-ins will be made "smarter" (as you said), then it
>> > will be a great enhancement.
>> >
>> > Speaking for us, performance and memory usage is always a concern. So it
>> > would be good to keep an eye on avoiding large new in-memory structures.
>> Template authors can always do something like
>> <#assign cheapProducts = prods?filter(...)>, and that will collect
>> everything into a List internally, as it's eager processing. If an
>> aggregating ?groupBy is concerning, then this is even more so.
> Hmm... well.... difficult....
> So, *<#assign cheapProducts = prods?filter(...)>* will create a new list,
> while the following does not:
>  <#list products?filter(it -> it.price < 1000) as product>
>     ${}
>   </#list>
> Right?
> Earlier you wrote:
> *"Of course these built-ins aren't specific to #list, they can be
> usedanywhere. Naturally, they can be chained as well:"*
> What would be a downside of allowing ?filter / ?map only in #list?

It makes them significantly less useful. A major annoyance that users
run into in FTL is that you can build a new sequence (wrapped List)
based on an existing one. They may want to do that, and then assign it
to a variable, or pass it to a custom macro as argument. (OK, you can,
with sequence concatenation, but that's very inefficient if you
exploit to build a sequence element by element.) ?filter and ?map
would help in lot of those use cases where the users wanted to build a
new sequence.

Speaking of which, nothing stops users from building gigantic
sequences from some iterable you provide with sequence concatenation.
Sure, it's less tempting to do than applying ?filter and ?map, but
still... users do it.

> I guess it makes it more complicated to explain.

That too, and also it must be quite off putting to discover a such
limitation. After all, it's natural to expect that if you can have
<#list someExp>, then you can factor out someExp into an earlier

Besides, if we really wanted to limit these to #list, then they would
be the part of the #list syntax, like <#list xs as x where>.
Kind of like SQL (yuck).

> Difficult tradeoffs here :) Sorry sometimes I get confused by jumping
> between lazy and eager processing.

Well, if you fear users jumping on ?filter/?map outside #list for no
good enough reason, there can be some option to handle that. But I
don't think restricting the usage to #list is a good compromise as the

>> I'm not sure how efficiently could a configuration setting catch these
>> cases, or if it should be addressed on that level.
> Maybe let's postpone configurability discussion a bit until the above is
> more clear.

In the light of the above, I think we can start thinking about that

Different... I have added some optimization to ?size. So for example
if you have <#if list?filter(foo)?size != 0>, then not only it will
not build any in-memory list (?size never does that, as it only has to
count), but it only fetches elements until it finds one that matches
the filter predicate, as at that point the comparison result already
can be known. This works with comparison with any integer literal, and
other comparison operators as well.

(Also, list?map(foo)?size basically falls back doing list?size.
Admittedly that has no much practical application, but still...)

 Daniel Dekany

View raw message