liquid
liquid copied to clipboard
Ternary operator feature support
I know this feature has been requested before in this thread: https://github.com/Shopify/liquid/issues/236
And based on 85 liking the idea, versus 2 not liking the idea says something.
But that issue was closed back in 2016, and as the docs says:
Things we will merge
- Features that are likely to be useful to the majority of Liquid users
I personally still see a great advantage in having the opportunity to use ternary operators, the code is way more slick and friendly to look at.
I saw the default
filter was suggested, but doesn't always come in handy, when using logic.
Without ternary
{% assign has_selected_variant = false %}
{% if product.selected_variant != nil %}
{% assign has_selected_variant = true %}
{% endif %}
With ternary
{% assign has_selected_variant = product.selected_variant != nil ? true : false %}
This or #1271 would be so clean! 🚀
Please implement this. Saving heaps of lines of unnecessary code.
This would be really handy and add readability to the code. I would love to see Liquid getting closer to JavaScript syntax (Ruby here also).
@dylanahsmith 😶
I saw the
default
filter was suggested, but doesn't always come in handy, when using logic.
It seems. like the difference between what you want and the default filter is the ability to specify the value to use when it is truthy.
The condition ? value_if_true : value_if_false
C-style syntax seems to those that aren't familiar with it. My bias would be to something closer to python style conditional expression syntax (value_if_true if condition else value_if_false
), which seems more readable and immediately understandable. However, preceding with a condition would actually make it easier to turn into a filter by replacing ?
and :
with the filter name and a keyword argument name.
Starting with a filter would make it much easier to introduce without worrying about backwards compatibility concerns. It wouldn't preclude the introduction of special syntax for it. It would actually make it easier to gauge adoption of the feature, that would help with justifying special syntax for making it more concise.
@dylanahsmith Would love to see an example of suggested filter option. Either way it would be an awesome feature, I think most liquid users would appreciate.
You thinking of something like this, or what is the idea of replacing ?: with filter names?
assign ternary = somelogic | truthy: 'something' | falsy: 'somethingelse'
I think this feature will take another decade to be considered by the staff, lol
You thinking of something like this, or what is the idea of replacing ?: with filter names?
assign ternary = somelogic | truthy: 'something' | falsy: 'somethingelse'
I was thinking it would be a single filter. We already have a default
filter, so we kind of want the inverse with an else
keyword argument. As in something more like
assign ternary = somelogic | if_truthy: 'something', else: 'somethingelse'
I'm just not sure about using the word "truthy" in the filter name. That is kind of a non-standard word that seems to be introduced to describe the way programming/template languages handle if
conditions. Although the concept has been documented in languages like liquid, normally it doesn't need to actually appear in the code due to if
preceding the condition, so it is implied that it is followed by a condition that is tested for whether it is "true". In this case, the condition precedes the filter name, unlike how if
is normally used in English for conditionals, hence the use of if_truthy
instead of if
in the example above.
Are there object-oriented programming languages that try to provide something like "if" as a method that we could take inspiration from? E.g. somelogic.if_truthy { 'something' }
could be a ruby method.
Possibly the awkwardness of the naming is why the C ternary syntax uses ?
to indicate the it is preceded by a condition instead of looking for an appropriate word.
How about just if
and unless
?
{%- assign somevar | if: 'something' -%}
{%- assign somevar | if: 'something', else: 'somethingelse' -%}
{%- assign somevar | if: 'something', 'somethingelse' -%}
{%- assign somevar | unless: 'something' -%}
{%- assign somevar | unless: 'something', else: 'somethingelse' -%}
{%- assign somevar | unless 'something', 'somethingelse' -%}
Personally, I like the one where else
is a param.
I already tried to explain why just an if
filter name would be confusing (the same applies to unless
)
In this case, the condition precedes the filter name, unlike how
if
is normally used in English for conditionals, hence the use ofif_truthy
instead ofif
in the example above.
E.g. {%- assign a | if: b, else: c -%}
reads as: "assign a if b, else b". That makes it seem equivalent to
{% liquid
if b
assign a
else
assign c
endif
%}
especially to python programmers, since python has the value_if_true if condition else value_if_false
syntax for ternary operators.
+1
+1
@dylanahsmith How about something like this, that would remove the confusion of the wording, even with the if/unless keywords. As it reads how you would return it
{%- liquid
assign a = 'a' | if: 'something true', then: 'b'
assign b = 'b' | unless: 'something true', then: 'a'
-%}
Or a combined wording, does seem more messy though
{%- liquid
assign a = 'a' | ifthen: 'something true', 'b'
assign b = 'b' | unlessthen: 'something true', 'a'
-%}
Oh, I had kept thinking that we would want the condition evaluated first, so having it as the filter input would make sense. However, it isn't like a filter is going to short circuit the evaluation of arguments anyways and the order of evaluation generally shouldn't matter in liquid, with avoiding liquid errors on the unused branch being a notable exception. If we really want short circuit evaluation, then that might be a good argument in favour of dedicated syntax.
If we do go with a filter, then having the condition as the first argument to the filter does allow it to be readable as well as consistent with python's ternary operation. In that case, I think we would want else:
as a keyword argument for the second argument. As in, value_if_true | if: condition, else: value_if_false
That seems fine at first, until realizing that filter argument expressions aren't consistent with condition expressions, so the product.selected_variant != nil
expression in the PR description wouldn't work in this context. Specifically, the lax liquid parser would parse {% assign has_selected_variant = true | if: product.selected_variant != nil, else: false %}
the same way as {% assign has_selected_variant = true | if: product.selected_variant, else: false %}
, which is quickly going to lead to confusion and frustration if we just added an if
filter.
It looks like we really do need to evolve the language itself, so that it has first class expression support, in which we could provide an actual ternary operator. E.g. we would ideally be able to actually specify something like a python ternary operator {% assign has_selected_variant = true if product.selected_variant != nil else false %}
and have the expected short-circuit evaluation. In that way, this is similar to https://github.com/Shopify/liquid/issues/138 in that it depends on having a way to evolve the language while continuing to provide backwards compatible support for existing code that we are committed to not breaking.
@dylanahsmith Appreciate the detailed response on this! What would be a realistic timeline look like for what seems to be a much more in depth task than what this originally was intended 😄
GPT4 totally told me I could use ternaries in liquid. It was upset with itself when I told it the bad news.
You are correct, and I apologize for the confusion earlier. Liquid does not support the ternary operator directly. My mistake!
+1
GPT4 totally told me I could use ternaries in liquid. It was upset with itself when I told it the bad news.
ChatGPT has a 100% failure rate when I've asked it for any Shopify Liquid or API help. Gets it wrong on the first attempt, and then either repeats the same mistake over and over, or hallucinates an answer to 'please' me 🥴
...anyway: +1 to ternary operators!