Logical operators

Overview

Go’s text/template package includes three logical operators to use in your Hugo templates: andor, 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.

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 }}
Last modified: