L'opérateur de coalescence (alias Elvis)

L’opérateur de coalescence est un raccourci pratique qui permet de fournir une valeur de secours lorsqu’une donnée est absente ou vide. Il simplifie l’écriture des conditions et évite de multiplier les tests explicites.
Aussi surnommé « Elvis operator » dans certains langages en raison de sa forme ?:
, il est utilisé pour écrire un code plus concis et lisible, notamment dans la sélection de valeurs par défaut.
Les origines de l’opérateur de coalescence
L’opérateur de coalescence a une histoire assez intéressante, qui commence bien avant son arrivée dans Blogger.
Dans la plupart des langages, la question de la “valeur par défaut” s’est posée très tôt. Comment écrire rapidement : « si telle valeur est vide ou nulle, alors prends celle-ci à la place » ? Pendant longtemps, les développeurs devaient recourir à des conditions complètes, souvent un peu lourdes à maintenir.
C’est dans le langage C# que l’on trouve une première réponse élégante : en 2003, Microsoft introduit l’opérateur ??
, baptisé null-coalescing operator. Il sert à renvoyer la première valeur si elle est non nulle, sinon la seconde. Cette petite invention s’est vite imposée comme un raccourci très apprécié.
Quelques années plus tard, des langages comme Kotlin ou Groovy reprennent le concept, mais avec une autre syntaxe : ?:
. C’est cette forme qui lui vaut le surnom d’« Elvis operator » — parce que les deux symboles, placés côte à côte, évoquent la banane légendaire du King.
Lorsque Blogger a mis à jour en 2015 son propre langage d’expressions dans les thèmes, l’équipe a retenu cette même écriture ?:
. Officiellement, il n’a jamais été vraiment nommé dans la documentation, mais il reprend exactement la logique de ses prédécesseurs : offrir une valeur de repli si la première est absente.
Aujourd’hui, il est utilisé partout dans les thèmes Modernes de Blogger, et même si son nom reste flou (« binaire », « coalescence », « Elvis »…), son rôle est clair : rendre le code plus concis et éviter des conditions trop verbeuses. C’est un bon exemple d’évolution où une idée née dans un langage de programmation s’est répandue jusque dans un DSL spécialisé comme celui de Blogger.
Les syntaxes d'écriture
L’opérateur de coalescence accepte deux formes d’écriture. La première, dite infixe, s’écrit sous la forme a ?: b
et peut être prolongée par d’autres ?:
pour comparer plusieurs valeurs successives. La seconde, appelée fonctionnelle, s’écrit ?:(a, b, c, …)
et permet de chaîner plusieurs alternatives de manière plus compacte. Dans les deux cas, le résultat est toujours la première valeur non vide trouvée parmi les opérandes. En pratique, la syntaxe infixe reste la plus lisible lorsqu’il n’y a que deux valeurs à tester, tandis que la syntaxe fonctionnelle est à privilégier dès qu’il y a plus de deux alternatives.
Noms | Opérateurs | Syntaxes | Opérandes | Résultat |
---|---|---|---|---|
Coalescence |
?: |
Syntaxe Infixe (par défaut) value1 ?: value2 Syntaxe Fonctionnelle ?:(value1, value2) |
2+ | La première valeur non vide parmi les opérandes |
Utilisation et règles
L’opérateur de coalescence permet de sélectionner la première valeur non vide parmi plusieurs alternatives. Il accepte toujours au moins deux opérandes, mais peut en chaîner davantage, aussi bien en syntaxe infixe
a ?: b ?: c
qu’en syntaxe fonctionnelle?:(a, b, c)
.-
Les opérandes peuvent être de n’importe quel type :
Une valeur explicite (texte, nombre, booléen,…),
Une donnée Blogger (
data:...
),Le résultat d’une expression Blogger (opération imbriquée).
Le résultat peut lui-même être utilisé dans une autre opération, à condition que son type corresponde à ce qui est attendu (par exemple, un nombre dans une addition).
-
Nature des valeurs
Les valeurs
false
et0
sont considérées comme non vides : elles peuvent être renvoyées telles quelles et ne déclenchent pas le fallback.Les chaînes vides (
""
) et les tableaux vides sont en principe considérés comme vides.Cas particulier : Certaines données actives mais dépourvues de contenu (comme
data:blog.metaDescription
) peuvent être interprétées au moment du parsing comme valides, empêchant le fallback de s’appliquer. Dans ce cas, l’opérateur peut renvoyer une chaîne vide. Pour contourner ce comportement, il est conseillé de tester explicitement la valeur attendue (par exemple avec!= ""
ou.length gt 0
).
-
Bonnes pratiques
Utiliser la forme infixe pour les cas simples à deux valeurs.
Privilégier la forme fonctionnelle dès qu’il y a trois valeurs ou plus : la lecture reste plus fluide.
Éviter les imbrications trop complexes : si la logique devient difficile à suivre, stocker un résultat intermédiaire avec
<b:with>
est plus clair et maintenable.
Quelques exemples
Deux opérandes
<img expr:src='data:view.featuredImage ?: "https://example.com/fallback.jpg"'/>
Cet exemple illustre l’usage le plus simple de l’opérateur de coalescence. On affiche l’image mise en avant de la vue courante si elle est définie ; sinon, on bascule automatiquement vers une image de secours définie en dur. C’est un cas typique où la syntaxe infixe suffit.
Plusieurs opérandes
<b:with value='?:(data:notId, data:view.postId, data:view.pageId, data:blog.blogId' var='id'> <b:eval expr='data:id'/> </b:with>
Ici, la syntaxe fonctionnelle met en avant toute sa puissance. L’opération teste successivement plusieurs identifiants possibles : une variable inexistante notId
, puis l’ID du post, ensuite l’ID de la page, et enfin l’ID du blog. Le premier trouvé est retenu et stocké dans la variable id
. Cette écriture reste lisible même avec plusieurs alternatives, là où la forme infixe deviendrait lourde.
Dans une inclusion commune
<b:loop values='?:(data:links, data:labels)' var='item'> <a expr:href='?:(data:item.href, data:item.target, data:item.url)'> <b:eval expr='?:(data:item.title, data:item.name)'/> </a> </b:loop>
Imaginons que ce code est implémenté dans une inclusion commune qui gère trois gadgets aux dictionnaires de données différents : PageList, LinkList et Labels. Le sélecteur de coalescence sert d’aiguilleur : il choisit d’abord le tableau links[]
(présent pour PageList et LinkList), sinon il bascule sur labels[]
(gadget Libellés). À l’intérieur de la boucle, il résout ensuite les écarts de schéma propriété par propriété.
- PageList →
links[]
avechref
(URL) ettitle
(intitulé). - LinkList →
links[]
avectarget
(URL) etname
(intitulé). - Labels →
labels[]
avecurl
(URL) etname
(intitulé).
La coalescence unifie ces variantes : ?:(data:item.href, data:item.target, data:item.url)
garantit une URL dans tous les cas, et ?:(data:item.title, data:item.name)
fournit un intitulé fiable. L’ordre des opérandes est important : on interroge d’abord les champs propres à links[], puis ceux de labels[].
Résultat : une seule inclusion, zéro branchement conditionnel, et un code lisible.