-
-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Filters feel inconsistent, brittle and poorly defined, partly because we're carrying over some or all of the behavior demonstrated by Shopify/liquid.
I want to be specific about the types of the arguments filters accept and I want to define automatic type coercion rules for each parameter.
We'll need to decide on a policy for how to handle values that can't be coerced to an acceptable type. Right now, filters will sometimes raise an exception and sometimes fallback to a default value.
find_index example
I'm conscious that introducing lambda expressions as filter arguments means we're effectively overloading some filters. Add legacy Shopify/liquid behavior when two arguments are given, and we have quite a mess of rules. In contrast, JavaScript, for example, has separate findIndex and indexOf Array functions that accept a function or value for comparison, respectively.
These examples attempt to illustrate the mess that we need to unravel.
This expects a to be an array of objects with string keys, and has ill-defined behavior when a contains items that are not objects.
{{ a | find_index: 'title', 'bar' }}
This is equivalent, but naturally handles items of any type thanks to variable lookup (path resolution) semantics.
{{ a | find_index: i => i.title == 'bar' }}
This has an implicit second argument of null, indistinguishable from an explicit nil/None/null.
{{ a | find_index: 'z' }}
Strings inputs are coerced to single-element arrays, like ["zoo"], resulting in surprising substring matching behavior. Here, we'll get an index of 0.
{{ 'zoo' | find_index: 'oo' }}
Ojects/hashes are also implicitly coerced to a single-element array. If obj is {"z": 42}, this will give us an index of 0, which is reasonable for find_index, but maybe not so for first.
{{ obj | find_index: 'z' }}
So will this.
{{ obj | find_index: 'z', 42 }}