Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ternary operator feature support #1264

Open
madsenmm opened this issue Jun 23, 2020 · 20 comments
Open

Ternary operator feature support #1264

madsenmm opened this issue Jun 23, 2020 · 20 comments

Comments

@madsenmm
Copy link

I know this feature has been requested before in this thread: #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 %}
@Curzey
Copy link

Curzey commented Jul 28, 2020

This or #1271 would be so clean! 🚀

@paulhuisman
Copy link

Please implement this. Saving heaps of lines of unnecessary code.

@mirceapiturca
Copy link

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).

@Curzey
Copy link

Curzey commented May 10, 2021

@dylanahsmith 😶

@dylanahsmith
Copy link
Contributor

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.

@madsenmm
Copy link
Author

@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'

@notrealdev
Copy link

I think this feature will take another decade to be considered by the staff, lol

@dylanahsmith
Copy link
Contributor

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.

@andershagbard
Copy link
Contributor

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.

@dylanahsmith
Copy link
Contributor

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 of if_truthy instead of if 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.

@pablogiralt
Copy link

+1

1 similar comment
@Jellyfishboy
Copy link

+1

@madsenmm
Copy link
Author

madsenmm commented Oct 5, 2022

@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'
-%}

@dylanahsmith
Copy link
Contributor

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 #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.

@madsenmm
Copy link
Author

@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 😄

@drnic
Copy link

drnic commented Aug 24, 2023

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!

@MariannaAtPlay
Copy link

+1

@indextwo
Copy link

indextwo commented Mar 5, 2024

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!

@mmatila
Copy link

mmatila commented Oct 8, 2024

+1 for ternaries! I also was bamboozled by ChatGPT's sweet little lies...

@madsenmm
Copy link
Author

madsenmm commented Oct 8, 2024

@dylanahsmith You still the man for this feature request? Or who do you reference nowadays on stuff like this?
Would be nice if it could be labeled as a Feature request as well.

maybe @karreiro have anything to add? 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests