Skip to content

Ternary operator support #236

Closed
Pym opened this Issue Jul 28, 2013 · 38 comments
@Pym
Pym commented Jul 28, 2013

Hello!

I think it would be awesome to implement ternary operator support like Twig does:

{{ foo ? 'yes' : 'no' }}

{{ foo ?: 'no' }} == {{ foo ? foo : 'no' }}
{{ foo ? 'yes' }} == {{ foo ? 'yes' : '' }}
@fw42
Shopify member
fw42 commented Aug 2, 2013

Hm I don't think we will implement this. Not a big demand for this at Shopify. Sorry.

@fw42 fw42 closed this Aug 2, 2013
@ajwhite
ajwhite commented Mar 19, 2014

+1, Would be a big help for basic ternary operations

{{ foo ? 'yes' : 'no' }} please

@caffinatedmonkey

+1, I think this is needed.

@mkdizajn

+1 must have,, gives the point of simplicity!

@getdave
getdave commented May 14, 2014

+1 for this please

@Rican7
Rican7 commented May 14, 2014

This would definitely be a helpful feature.
+1 here

@Rican7
Rican7 commented May 14, 2014

PS: "Not a big demand for this at Shopify" isn't the best answer for why a feature shouldn't exist in an open source project. :/

@Pym
Pym commented May 14, 2014

@Rican7 yeah right? That's why I decided to never use liquid again :D

@nickpearson

I don't work at Shopify and I don't speak for them, but I thought this was worth commenting on.

Liquid is a Shopify project that they were kind enough to open source. If a request comes in for a feature that won't benefit Shopify and its customers, it makes sense that Shopify wouldn't spend resources implementing it and (from their perspective) adding bloat to the project. However, the beautify of open source is that you can fork the project and implement whatever features you want.

For what it's worth, I agree with you that this would be a nice feature. Unfortunately it goes against Liquid's style of using just values, variables, and filters (and not expressions) for output, so I don't expect it to be implemented.

For some of my projects, I add a custom if filter. It basically works like a ternary expression, but it's written as a filter: {{ foo | if: 'yes', 'no' }}. The yes is outputted if foo is truthy, and no is outputted otherwise. The second (else) argument is optional. There's also an unless that's the opposite of if. Here's a super simple implementation:

module TernaryFilters
  def if(value, true_output, untrue_output = '')
    value ? true_output : untrue_output
  end

  def unless(value, untrue_output, true_output = '')
    value ? true_output : untrue_output
  end
end

Try it in an irb session:

# paste the module code from above

template = Liquid::Template.parse("{{ foo | if: 'yes', 'no' }}")
template.render({ 'foo' => true  }, filters: TernaryFilters) # => "yes"
template.render({ 'foo' => false }, filters: TernaryFilters) # => "no"

You of course may want to handle the value differently, such as treating a zero or an empty string as falsy. Hopefully this helps someone who wants a brief syntax for conditional output, Liquid-style.

@fw42
Shopify member
fw42 commented May 14, 2014

@Rican7: Maybe we have different understandings of what open source software means. To me, it means that we will publish the code that we use ourselves (!) so that others can benefit from it (for free). We are totally cool with you forking this project and implementing whatever features you need for yourself. We are happy to consider any suggestions that you make, but the final decision of whether we will merge it into our version of Liquid is up to us. You have no right at all to demand features being included and I think "we don't need this feature at Shopify" is a totally legit reason to reject things. If you don't like it, don't use it.

Back to topic: I'm totally open to reconsider this decision. @Shopify/liquid, any more thoughts on the usefulness of this? @Shopify/design-gurus might have opinions too. Would this be helpful?

@ajwhite
ajwhite commented May 14, 2014

@nickpearson makes a good point that Liquid folllows an approach of using just values, variables, and filters, rather than expressions, for output, however that can be a little constricting for many edge cases developers may encounter. Sure we can still achieve the desired output with a different set of variable assignments and conditions, but that, to us, is just a work around for not having an easy expression to call.

So without asking to review Liquid's approach to have a higher focus on expressions, it would be useful to introduce some basic/fundamental expressions that have low complexity and introduce an easier process of spitting out information, ternary support being one.

@fw42 Thanks for considering this as a possibility per discussion.

@Rican7
Rican7 commented May 14, 2014

I want to make it clear that I wasn't trying to insult anyone here. If I did, I apologize.

I was simply trying to say that its a very closed off approach to just deny a feature and close the issue without further conversation from the community. The decision absolutely comes down to the owner of the project, and pandering to every community request isn't an option either, but its discouraging to see such a terse response on a feature request that may prove valuable to the community.

Yes, the beauty of open source is that you're giving your code away for free, something that I believe anyone could appreciate. Its also under a very lenient license (MIT), so it could be modified and redistributed. However liquid has quite a large user base and usage pattern that isn't easily controlled by the user due to one fact: GitHub uses Jekyll, which uses Liquid templating, for both generating repo and user pages, so simply forking the project doesn't allow for the same workflow here.

Either way, I'm happy to see the reconsideration here. Thanks for listening! :+1:

@fw42 fw42 reopened this May 14, 2014
@fredryk
fredryk commented May 14, 2014

In what we deal with day to day, I don't see a huge use for this… unless just to save a couple lines of code. I'd love to see a real world use case though.

@ajwhite
ajwhite commented May 14, 2014

@fredryk Basic example..

{% if product.available %}
  <link itemprop="availability" href="http://schema.org/InStock" />
{% else %}
  <link itemprop="availability" href="http://schema.org/OutOfStock" />
{% endif %}

versus

<link itemprop="availability" 
   href="http://schema.org/{{ product.available ? 'InStock' : 'OutofStock' }}" />

Just one off the top of my head. It's pretty much a code saver, but it'd be a great-to-have :smile:

Or conditional classes, it's much more conventional to have

<div class="{{ product.available ? 'available' : 'outofstock' }}"> .. </div>

versus

{% if product.available %}
<div class="available">
{% else %}
<div class="unavaialble">
{% endif %}
   .. content ..
</div>
@fredryk
fredryk commented May 14, 2014

@ajwhite, we could simplify things a bit more already:

{% if product.available %}
<div class="available">
{% else %}
<div class="unavaialble">
{% endif %}
   .. content ..
</div>

Can be shortened down:

<div class="{% if product.available %}available{% else %}unavaialble{% endif %}">
   .. content ..
</div>

I like the use case though. Thanks for posting it! :)

@ajwhite
ajwhite commented May 14, 2014

@fredryk Ah yes, can I embarrassingly remove that comment now? :wink:

Good point though, that isn't too ugly, but also slightly less friendly as a ternary. Works though

@fw42 fw42 closed this Aug 4, 2014
@fulldecent

Here is the use case:

<h1>REPLACE ME</h1>

Filling in by finding the first available:

  • page.heading
  • page.title
  • site.title
@TWiStErRob

Here's another one:

{% assign postCount = site.categories[other_category.slug].size %}
{% unless postCount %}{% assign postCount = 0 %}{% endunless %}
Versus
{% assign postCount = site.categories[other_category.slug].size ?: 0 %}
@carolineschnapp

I find Ternary operator construct unnecessarily hard to read in Liquid. To me anyway, Liquid is not a programming language, it is meant to be super simple. I am all for making Liquid do things that were not possible before, when these things are most needed, but since Liquid can do in a more verbose ( in my opinion easier to read ) way what a Ternary operator would allow, then this would make me give a :-1: .

@ajwhite
ajwhite commented Jun 12, 2015

To me anyway, Liquid is not a programming language, it is meant to be super simple.

Correct, but when you can make assignments, it would be nice to have decent support in that. Nothing crazy, but something like a ternary makes an assignment based on a condition a lot easier to write.

I find Ternary operator construct unnecessarily hard to read in Liquid.

I disagree, using @TWiStErRob's example, i think

{% assign postCount = site.categories[other_category.slug].size ?: 0 %}

reads pretty easily. It feels a lot easier to read than

{% assign postCount = site.categories[other_category.slug].size %}
{% unless postCount %}{% assign postCount = 0 %}{% endunless %}

but since Liquid can do in a more verbose ( in my opinion easier to read ) way what a Ternary operator would allow

I guess that comes down to personal preference. I, personally, don't think multi-lined assignments due to verbosity is easier to read. Being used to ternaries, it feels like extra work to understand the assignment by having to read multiple lines of conditional reassignments.

@TWiStErRob

I guess that comes down to personal preference.

I think this is key here, liquid is a framework/library. How one uses a library is their problem. But if a library lacks a feature that's everyone's (at least those who want to use it).

I could also argue for size to return 0 when the object is null, but that's a different issue.

@TWiStErRob

Hmm, lookey here, it's not ternary, but at least Elvis is alive! (added in #267)
{% assign postCount = site.categories[other_category.slug].size | default: 0 %}
I just wish GitHub pages/Jekyll would bump to 3.x...

@ajwhite
ajwhite commented Jun 17, 2015

Nice, even an "Elvis operator" is a nice step up. Would still be nice to have a true ternary, but this is a good find

@pjmay
pjmay commented Nov 30, 2015

@fredryk you can simplify it even more:

<div class="{% unless product.available %}un{% endunless %}available">
   .. content ..
</div>
@Dorian
Dorian commented Jan 26, 2016

:+1: for ternary operators, assignments are much more complicated without it.

@bbuie
bbuie commented Mar 11, 2016

This is a good reason why Shopify hasn't become the clear leader in ecommerce. They think supporting developers is not in their best interest. Unfortunately, they don't realize the power of a strong recommendation from a developer to a potential customer.

@nickpearson

Yes, because they do not implement every single requested feature in an excellent library they make freely available to everyone, Shopify hates developers.

Sure, ternary operator support would be great, but your claim is unreasonable and way out of proportion. And if I remember correctly, they do accept pull requests.

@bbuie
bbuie commented Mar 11, 2016

I just re-read my comment and it did sound a bit harsh. :(

That said, the only reason I know Liquid is because they require it to build their themes. I'm a customer myself, and I've developed themes for many of their customers, so don't think I'm using a free library and then complaining.

In addition, this is just one of the many examples where it is clear that shopify ignores requests even with a need. This isn't helping them become a clear leader.

I've been developing ecommerce sites for almost a decade and continue to have a high hope that someone will emerge as the leader. I really thought Shopify would, and it has a lot going for it, but I can see they're missing the opportunity to cater to developers and thus grow their market share.

@fw42
Shopify member
fw42 commented Mar 11, 2016

Thanks for sharing your opinion, and I understand your frustration, but this GitHub repository is not the right place to discuss this. This is for discussions around the Liquid open source Ruby library, not about Shopify the company or Shopify the product (or even Shopify's use of the Liquid library).

@bbuie
bbuie commented Mar 11, 2016

You're right. Sorry about that. I just found this page searching for this feature and didn't realize the context.

@ajwhite
ajwhite commented Mar 11, 2016

We've had discussions above related to how this can be done with the existing support

class="{% if foo %}foo{% else %}bar{% endif %}"

This works. It's not beautiful, but it does support the use case.

@fw42 has made it clear that the maintainers are not likely going to introduce this feature. But we should keep in mind that this is an open source project with a lot of contributors. I'm sure the project maintainers would be happy to look at a contribution introducing this support, but this has been closed because it's not on their development road map. No reason we can't put forward a solution as a community contribution to the project.

@ajwhite
ajwhite commented Mar 11, 2016

Although I believe @bbuie's criticism is likely due to the original reason the issue was closed

Not a big demand for this at Shopify. Sorry.

In contrast to

This is for discussions around the Liquid open source Ruby library, not about Shopify the company or Shopify the product (or even Shopify's use of the Liquid library).

@bbuie
bbuie commented Mar 11, 2016

@ajwhite that is correct.

The reason I was hoping for this is I need to do something like this:

{% assign is_true = vav < 0 ? true : false %}

Is that possible another way? I hate to write 5 lines of code for something that should take one. Less code = less bugs. :)

@ajwhite
ajwhite commented Mar 11, 2016

Yes, even simpler without the unsupported ternary :wink:

{% assign is_true = vav < 0 %}

vav < 0 is either true or false

Unless you're just describing a simplified example where you wouldn't be using booleans based on the expression, something like:

is_something = vav < 0 ? 'not a boolean' : 'also not a boolean'

In which, no, it'd still have to be expressed as

{% if vav < 0 %}
{% assign is_something = 'yes it is' %}
{% else %}
{% assign is_something = 'no its not' %}
@bbuie
bbuie commented Mar 11, 2016

@ajwhite Thanks. I tried that but it wasn't working so I went on the search. This particular project is outside Shopify, so I wonder if they're out of date.

@pushrax
Shopify member
pushrax commented Mar 11, 2016

Shopify is always running the latest master branch of Liquid.

@bbuie
bbuie commented Mar 11, 2016

@pushrax Thanks, that is good to know. What I meant was that the project I'm working on may not be using the latest master branch because it is a project outside of Shopify.

@pushrax
Shopify member
pushrax commented Mar 11, 2016

I see, totally misunderstood you. Perhaps it is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.