mercredi 14 décembre 2022

Méthodes monadiques sur std::optional

Voilà que C++ se prend pour Haskell ! Maintenant, nous avons une belle interface monadique pour std::optional, les méthodes and_then, transform, or_else, qui permettent de chainer des appels sur un optionel. Je me suis demandé si le compilo pouvait optimiser entre les appels, et j'ai donc demandé au fidèle godbolt ce quí il en pensait. Le résultat est impressionnant. Voici deux fonctions qui font la même chose, l'une utilisant l'approche monadique (g++ 12.2, options -O3 -std=c++23):

#include <optional>

int f(const std::optional<int>& opt)
{
    return opt
    .transform([](auto&& val) { return val + 3;})
    .transform([](auto&& val) { return val - 11;})
    .value_or(7);
}

int g(const std::optional<int>& opt)
{
    if (opt)
    {
        return *opt + 3 - 11;
    }
    else
    {
        return 7;
    }
}

G++, sans broncher, nous sort, dans les deux cas, le même code optimisé aux petits oignons:

        cmpb    $0, 4(%rdi)
        movl    $7, %eax
        je      .L1
        movl    (%rdi), %eax
        subl    $8, %eax
.L1:
        ret

À noter que clang, encore mieux, nous débarasse carrément du saut conditionnel !

        movl    (%rdi), %ecx
        addl    $-8, %ecx
        cmpb    $0, 4(%rdi)
        movl    $7, %eax
        cmovnel %ecx, %eax
        retq

Ils sont forts, ces concepteurs de compilos. La conclusion, c'est donc que oui, le compilo peut optimiser à travers les appels monadiques. Mangez-en donc !

Aucun commentaire: