What is a Guard clause?

Asked

Viewed 464 times

5

What is a Guard clause?

Possible translations and synonyms:

  • Custody clause
  • Guard status
  • Sentinel clause
  • Prevention clause
  • Protection clause

Fuller definition.

What are its advantages? The code is more readable with them (as a rule)?

  • See function Guards, which is something built-in in Elixir: https://elixirschool.com/pt/lessons/basics/functions/#Guards

3 answers

5


In the context of the question are those conditions that prepare the ground for the actual execution of the code filtering out what will do and especially can be done.

These are conditions that the algorithm needs to ensure before performing the action it is prepared to do.

Some people know this pattern as precondition and in fact is very much used as contracts of a function.

It can be from a basic validation of an argument received to evaluate if it is of the expected type, if it is not null, if it is within a certain range, or if some data is in a given state, even if it is not about the arguments of the function (although this would be done on the object that was received implicitly by a method). And it can be a business rule validation how to determine if you have enough balance to accomplish that (a serve for example).

Examples:

draw() {
    if (!isVisible()) return; //se não estiver visível não tem porque desenhar
    ...
}

bool saque(int valor) {
    if (saldo - valor + limite < 0) return false;
    ...
}

T getElement(int index) {
    if (index >= this.length) throw new OutOfBounds();
    ...
}

T join(T a, T b) {
    if (a == null) return b; //não precisa fazer a operação se o outro não existe
    if (b == null) return a;
    ...
  }

It doesn’t have to be just one condition, and it can include all that is necessary.

Some languages have mechanisms that facilitate this, which allow to avoid certain checks, at least of their mechanism. Some have even a if in a special way that facilitates this, or that gives more semantics to this part. But it’s what I always talk about, is a Pattern design so important that they put in the syntax.

Usually she opposes putting several ifnested or take further decisions in the midst of execution. With this pattern you tend to make it more readable by increasing the programmer’s productivity by seeing right away if everything is ok. It becomes much easier to analyze the necessary conditions for the use of what is often important.

And there is gain in execution the performance will tend to be better because not waste time with something that has no future.

It has to do with that too: Why should I only use a "Return" in each function?.

4

Safekeeping clause is a clause that allows you to validate a variable, usually an input, and ensure that it has a value that you can use in the code.

It is not a business validation, for example if a date is later than the current date, it is for example:

  • If a value is not null;
  • If a value of an identifier number is not zero;
  • If a string is not null or empty;
  • If a dependency injection has been correctly injected

Some examples only, but the goal is to safeguard the method/function/module that the values have the minimum to be able to continue with the execution of the code.

See for example this code:

public void Calcular(AlgumaClasse obj, int valor)
{
   var x = obl.Total / valor;
}

What will happen if the obj is void, or valor is equal to zero? Will give zero reference and/or division by zero.

A Guard clause here may be so:

public void Calcular(AlgumaClasse obj, int valor)
{
   if (obj == null)
   {
       throw new ArgumentNullException("obj não pode ser nulo");
   }

   if (valor == 0)
   {
       throw new ArgumentInvalidException("valor não pode ser zero");
   }

   var x = obj.Total / valor;
}

Therefore the code would have a safeguard with poorly informed values, remembering that it is only an example of the structure of how to store the code, which can be implemented in several ways.

Expressions can be used to validate. In C# we may have:

var total = obj == null ? 0 : obj.Total;
var total = obj?.Total;  // só exemplo, total sera null, vai falhar em seguida
var div = valor == 0 ? 1 : valor;

1

Roughly

Guards is a mechanism that allows the compiler to infer the state of a variable.

Its implementation depends on the language, but a widely used type of guard is to protect the code from accessing a null reference. You have this mechanism in languages like Kotlin, Typescript and C# (above version 8).

How it works:

// uma variável null-able do tipo inteiro é declarada
val i: Int? = null

// uma variável não null-able do tipo inteiro é declarada
val j: Int = 10

// com o mecanismo de guards ativado, isso resulta num erro de compilação
// pois i não é garantido de ser um inteiro válido
val soma1 = i + j

// utilizando uma condição de guarda, o código se torna válido, pois aqui é
// possível inferir que j será somado com um valor válido
val soma2 = (i ?: 0) + j

// aqui temos uma capsula de guarda, o compilador consegue inferir
// que dentro desse escopo, i não é null
if (i != null) {
    // utilizar i como um inteiro dentro desse escopo é válido
    var soma3 = i + j
}

This mechanism can also be used to infer the type of the variable, for example, in Typescript, where variables can be declared as algebraic type:

function test(valor: number | number[]) {
    // dentro desse contexto, valor pode ser tanto um número, quanto um array de números
    // portanto é necessário utilizar algum tipo de guarda para tratarmos a variável

    if (Array.isArray(valor)) {
        // Array.isArray define uma guarda, dentro desse escopo o compilador nos
        // permite tratar valor como um array

    } else {
        // A guarda também permite inferir que dentro desse escopo, valor não é
        // um array, e logo é possível trata-lo como um número nesse escopo
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.