Strict and relaxed boolean operators

docs state below:

As a rule of thumb, use and , or and not when you are expecting booleans. If any of the arguments are non-boolean, use && , || and ! .

One special trick which you can do with || is to assign default value when something is nil:

def id(opts) do
  id_prefix = opts[:id_prefix] || "default_prefix"
  #... do something.
end

|| becomes tricky for booleans when it is used for assigning default values :

def verify(id, opts) do 
  # this will result in a bug - validate_prefix? will not ever be false (for booleans)
  validate_prefix? = opts[:validate_prefix] || true # this will result in a bug - validate_prefix? cannot be false
  #  do something
end

Calling verify/2 with opts , opts2, opts3:

# works good - validate_prefix? will be true
opts = %{validate_prefix: true} 
verify("abc-123", opts)
# works good - true will be assigned (default value)
opts3 = %{} 
verify("abc-123", opts1)
# bug - disabling prefix validation is not possible due to use of ||
opts2 = %{validate_prefix: false} 
# this will be ignored and default value true will be assigned
# default value true will be assigned as false || true is always true
verify("abc-123", opts2)