-
Notifications
You must be signed in to change notification settings - Fork 15
Truthiness
Shopify's basic definition of truthiness is fairly straightforward: nil
and false
are FALSE and everything else is TRUE.
However, Shopify liquid has evolved a proliferation of inconsistent ad-hoc value comparison strategies, many of which confuse most designers and developers. For example, some comparisons will act differently depending on which Ruby libraries are enabled, meaning that liquid code is not portable from one environment to another. Also, some comparisons will return a value which is neither true nor false. Some comparisons are inconsistent when compared with nil. Some liquid types have Liskov violations and depend on underlying object implementations of the object being compared---and sometimes will return an unexpected error. Worse, comparisons may return different results depending on whitespace around the comparison operator. Also, there's a difference between variables which are unset and return something called an EmptyDrop
(i.e. "truthy" but "empty"), and values that are nil
("not truthy" but "not empty" either).
Ultimately, Liquid.NET is mostly compatible with Shopify Liquid, but greatly simplifies the rules to minimize the number of unpleasant surprises.
Firstly, all variables in Liquid.Net are either string
, numeric
, boolean
, collection
, hash
, date
or the special range
type (which won't be discussed here). A variable can take the value nil
. There's no such thing as a "Drop" or any sort of custom object, so any object-like thing you encounter will have already been converted to a hash
. Unset values are nil
.
The simplest comparison uses no operators---it just checks for the truthy value of a variable, i.e. whether it's nil
or false
.
{% if '1' %}truthy{% else %}falsy{% endif %}
--> truthy
{% if false %}truthy{% else %}falsy{% endif %}
--> falsy
Comparing two values with ==
will check to see if the type and value are the same.
{% if 3 == 3 %}truthy{% else %}falsy{% endif %}
--> truthy
{% if 3 == '3' %}truthy{% else %}falsy{% endif %}
--> falsy
Some keywords in ActiveSupport-enhanced Shopify Liquid are empty
, blank
, present
and nil
. You can check to see if a variable IS empty, blank, present or nil by using the comparison operator. To be clear, {% if x == empty %}
does not mean if value x equals the value empty, instead it means if value x is empty. You might have noticed some people using the Ruby-ish syntax {% x.empty? %}
, {% x.blank? %}
, or {% x.present? %}
.
In Liquid.NET, the "?" operators (such as .blank?
work exactly as do the equivalent "double equals" operators (such as == blank
), and they operate on all values. Liquid.NET also allows the use of "!=".
The empty
, blank
, present
keywords return true
when used with the ==
operator the following cases:
-
empty
: Returns true if 1) a value isnil
, OR 2) a value is an emptystring
without whitespace OR 3) The value iscollection
with no elements OR 4) The value is ahash
with no keys. -
blank
: Returns true if 1) a value isnil
, OR 2) a value is an emptystring
or only whitespace OR 3) The value iscollection
with no elements OR 4) The value is ahash
with no keys. You would useblank
where you would useString.IsNullOrWhiteSpace()
in C# on strings, or! x.Any()
on collections. -
present
: returns true if the value is not blank. Present is intended to be used as "not nil and not whitespace", i.e. "Is there a value present that can be displayed".
In my experience, the main source of confusion in Shopify liquid is that the "==" operator is overloaded and does two different things. Whenever you see == empty
, == blank
or == present
, you should think "IS empty", "IS blank" or "IS present". If you see myvar == nil
, or myvar == true
you are specifically checking if myvar
has the value nil or myvar
is false.
Another way of looking at it is that in Liquid.NET, ==
works like JavaScript's ===
operator in that it does not do type casting, except when used as an alias for checking for blank, empty, or present.