Logical operators
Overview
Go’s text/template package includes three logical operators to use in your Hugo templates: and
, or
, and not
. A common misconception is that these operators return either true
or false
. That is correct for the not
operator, but incorrect for and
and or
.
The and
and or
operators return a thing. That thing could be a string, an integer, a float, a slice, a map, a page collection, a boolean value, etc.
For example:
{{ and "a" "b" }} --> b (string)
Then why does this work?
{{ if and "a" "b" }}
...
{{ end }}
The construct above works because the conditional statements if
, with
, and range
determine which block of code to execute based on whether the argument is truthy or falsy. Although true
is truthy and false
is falsy, they are not the only truthy and falsy values.
The Mozilla Developer Network defines truthy
and falsy
as follows:
- truthy
- A truthy value is a value that is considered
true
when encountered in a Boolean context. - falsy
- A falsy value is a value that is considered
false
when encountered in a Boolean context.
The documentation for Go’s text/template package states:
The empty [ falsy ] values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero.
In addition to the values described above, Hugo also treat zero time.Time
values as falsy
. The zero date, formatted per ISO 8601, is 0001-01-01T00:00:00+00:00.
Everything else is truthy.
Why is this important? By returning a thing instead of true
or false
, the and
and or
operators can help up to simplify our template code. See the examples at the end of this article.
and
The and
operator is variadic; it accepts a variable number of arguments. Go’s documentation provides this description:
Returns the boolean AND of its arguments by returning the first empty argument or the last argument. That is, “and x y” behaves as “if x then y else x.” Evaluation proceeds through the arguments left to right and returns when the result is determined.
To simplify the above:
Returns the first falsy argument. If all arguments are truthy, returns the last argument.
For example:
{{ and 1 0 "" }} --> 0 (int)
{{ and 1 false 0 }} --> false (bool)
{{ and 1 2 3 }} --> 3 (int)
{{ and "a" "b" "c" }} --> c (string)
{{ and "a" 1 true }} --> true (bool)
or
The or
operator is variadic; it accepts a variable number of arguments. Go’s documentation provides this description:
Returns the boolean OR of its arguments by returning the first non-empty argument or the last argument, that is, “or x y” behaves as “if x then x else y”. Evaluation proceeds through the arguments left to right and returns when the result is determined.
To simplify the above:
Returns the first truthy argument. If all arguments are falsy, returns the last argument.
For example:
{{ or 0 1 2 }} --> 1 (int)
{{ or false "a" 1 }} --> a (string)
{{ or 0 true "a" }} --> true (bool)
{{ or false "" 0 }} --> 0 (int)
{{ or 0 "" false }} --> false (bool)
not
The not
operator takes a single argument. Go’s documentation provides this description:
Returns the boolean negation of its single argument.
Unlike the and
and or
operators, the not
operator always returns a boolean value.
{{ not true }} --> false (bool)
{{ not false }} --> true (bool)
{{ not 1 }} --> false (bool)
{{ not 0 }} --> true (bool)
{{ not "x" }} --> false (bool)
{{ not "" }} --> true (bool)
Use the not
operator, twice in succession, to cast any value to a boolean value. For example:
{{ 42 | not | not }} --> true (bool)
{{ "" | not | not }} --> false (bool)
Examples
Get default values
These are equivalent:
{{ or .Params.foo "default value" }}
{{ default "default value" .Params.foo }}
Avoid nested conditionals
Instead of this:
{{ if .Params.showCoverImage }}
{{ with .Resources.Get "cover.jpg" }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}">
{{ end }}
{{ end }}
Do this:
{{ with and .Params.showCoverImage (.Resources.Get "cover.jpg") }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}">
{{ end }}