Opérateur conditionnel ternaire
En programmation informatique, l'opérateur conditionnel ternaire est un opérateur ternaire qui renvoie l'une de deux valeurs en fonction d'une expression booléenne. Cet opérateur est également connu sous les noms d'opérateur conditionnel, si ternaire, si immédiat ou si en ligne (iif). Bien que de nombreux opérateurs ternaires soient théoriquement possibles, l'opérateur conditionnel est couramment utilisé et les autres opérateurs ternaires sont rares ; c'est pourquoi la variante conditionnelle est généralement désignée comme « l'opérateur ternaire ».
La syntaxe type d'une expression utilisant l'opérateur est la suivante : si a alors b sinon c ou a ? b : c. On peut le lire à haute voix ainsi : « si a, alors b ; sinon c ». La forme a ? b : c est la plus courante, mais il existe d'autres syntaxes. Par exemple, Raku utilise la syntaxe a ?? b !! c pour éviter toute confusion avec les opérateurs infixes ? et !, alors qu'en Visual Basic, cela prend la forme Iif(a, b, c).
Cette construction apparaît pour la première fois dans CPL, où une syntaxe équivalente pour a ? b : c est a → b, c[1],[2].
Motifs
Tâche
La valeur de l'opérateur peut être assignée à une variable. Dans un langage à typage faible, le type de données de la valeur sélectionnée peut déterminer le type de la valeur assignée. Dans un langage à typage fort, les deux expressions de valeur doivent donner lieu à un type compatible avec la variable cible.
Cet opérateur fonctionne de manière similaire aux expressions conditionnelles (if-then-else) dans les langages de programmation fonctionnelle, tels que Scheme, ML, Haskell et XQuery, car dans ces langages, la structure if-then-else constitue une expression et non une instruction.
L'opérateur permet d'initialiser une variable à l'aide d'une seule instruction, alors qu'il faudrait autrement plusieurs instructions. Son utilisation lors de l'affectation d'une variable réduit le risque de bogue lié à une affectation erronée, car la variable affectée n'est déclarée qu'une seule fois.
Par exemple, en Python :
x: str = 'foo' if b else 'bar'
au lieu de :
x: str
if b:
x = 'foo'
else:
x = 'bar'
Dans un langage à portée de bloc, une variable doit être déclarée avant l'instruction if-else. Par exemple :
std::string s;
if (b) {
s = "foo";
} else {
s = "bar";
}
L'utilisation de l'opérateur conditionnel simplifie cela :
std::string s = b ? "foo" : "bar";
De plus, comme l'initialisation fait désormais partie de la déclaration, et non plus d'une instruction distincte, l'identificateur peut être une constante. Par exemple :
const std::string s = b ? "foo" : "bar";
Sélecteur de cas
L'opérateur conditionnel peut être utilisé pour les sélecteurs de cas. Par exemple :
véhicule = arg == 'B' ? bus :
arg == 'A' ? avion :
arg == 'T' ? train :
arg == 'C' ? car :
arg == 'H' ? cheval :
pied ;
Variations
La syntaxe et la sémantique de l'opérateur varient selon le langage.
Parmi les principales différences, on peut citer la possibilité pour les expressions d'avoir des effets de bord et la présence ou non, dans le langage, d'une sémantique d'évaluation par court-circuit (de), selon laquelle seule l'expression sélectionnée est évaluée.
Si un langage prend en charge les expressions ayant des effets de bord mais ne spécifie pas d'évaluation par court-circuit, il existe alors une distinction supplémentaire quant à l'expression qui est évaluée en premier. Si aucun ordre n'est garanti, il faut déterminer si le résultat est alors considéré comme indéterminé (la valeur obtenue selon « un certain » ordre) ou indéfini (n'importe quelle valeur choisie au gré du compilateur face aux effets de bord, voire un plantage).
Si un langage n'autorise pas les effets de bord dans les expressions (ce qui est courant dans les langages fonctionnels), l'ordre d'évaluation n'a alors aucune incidence sémantique — même s'il peut néanmoins déterminer si une récursion infinie s'achève ou avoir d'autres implications en termes de performances (dans un langage fonctionnel utilisant des expressions de correspondance, l'évaluation en court-circuit est inhérente, et les utilisations naturelles de l'opérateur ternaire sont moins fréquentes ; ce point n'est donc pas très préoccupant).
C'est pourquoi, dans certaines langues, la forme de l'énoncé r = condition ? expr1 : expr2 peut avoir une sémantique légèrement différente de celle de la forme conditionnelle en bloc if (condition) { r = expr1; } else { r = expr2; }.
Dans presque toutes les langues de programmation, l'opérateur ternaire est associatif (en) à droite, de sorte que a == 1 ? "one" : a == 2 ? "two" : "many" se lit intuitivement comme a == 1 ? "one" : (a == 2 ? "two" : "many"). Cela signifie qu'il peut être enchaîné de la même manière qu'une chaîne if ... else if ... else if ... else. La principale exception est PHP, où l'association se fait par la gauche (de sorte que la même expression donne (a == 1 ? "one" : a == 2) ? "two" : "many", ce qui correspond rarement à ce à quoi s'attend le programmeur)[3] avant la version 8, et est non associative par la suite[4].
De plus, dans tous les langages de la famille C et dans bien d'autres, l'opérateur conditionnel ternaire a une faible priorité.
Équivalence binaire
L'opérateur ternaire peut également être considéré comme une opération de correspondance binaire.
En R — et dans d'autres langages prenant en charge les tuples d'expressions littérales, on peut simuler l'opérateur ternaire à l'aide d'une expression R du type c(expr1,expr2)[1+condition] (cette expression est légèrement plus naturelle dans les langages utilisant des indices à base 0).
Les expressions ternaires imbriquées peuvent être simulées comme suit : c(expr1,expr2,expr3)[which.first((c(cond1,cond2,TRUE))] où la fonction which.first renvoie l'index de la première valeur vraie dans le vecteur de conditions. Il convient de noter que ces deux équivalents de la fonction map sont des opérateurs binaires, ce qui montre que l'opérateur ternaire est ternaire sur le plan syntaxique, et non sémantique. Ces constructions peuvent être considérées comme une forme atténuée de curryfication reposant sur la concaténation de données plutôt que sur la composition de fonctions.
Si le langage propose un mécanisme de futures ou de promesses, l'évaluation par court-circuit peut parfois être simulée dans le cadre d'une opération de mappage binaire.
Exemples
Ada
L'édition 2012 d'Ada a introduit les expressions conditionnelles (utilisant if et case), dans le cadre d'un ensemble élargi d'expressions comprenant les expressions quantifiées et les fonctions d'expression. La justification d'Ada 2012[5] explique pourquoi Ada ne les avait pas encore intégrés auparavant, ainsi que les raisons pour lesquelles ils sont désormais ajoutés, notamment pour prendre en charge les « contrats » (une autre nouveauté).
Pay_per_Hour := (if Day = Sunday then 12.50 else 10.00);
Lorsque la valeur d'un if_expression est elle-même de type booléen, alors else peut être omis, la valeur étant vraie. Plusieurs conditions peuvent être enchaînées à l'aide de elsif.
Algol 60
Algol 60 a introduit les expressions conditionnelles (conditions ternaires) dans les langages de programmation impérative.
Cette instruction conditionnelle :
integer opening_time;
if day = Sunday then
opening_time := 12;
else
opening_time := 9;
On peut l'écrire autrement en utilisant l'opérateur conditionnel :
integer opening_time;
opening_time := if day = Sunday then 12 else 9;
Algol 68
Les clauses de sélection d'Algol 68 (clauses « if » et « case ») prennent en charge les éléments suivants :
- Clause « single if »
if condition then statements [ else statements ] fiou en forme brève :( condition | statements | statements )
- Clause « if choice » enchaînée
if condition1 then statements elif condition2 then statements [ else statements ] fiou en forme brève :( condition1 | statements |: condition2 | statements | statements ).
Bash
Il existe un véritable opérateur ternaire pour les expressions arithmétiques :
((result = condition ? value_if_true : value_if_false))
Pour les chaînes de caractères, il existe des solutions de contournement, comme par exemple :
result=$(if condition ; then echo "value_if_true" ; else echo "value_if_false" ; fi)
condition peut être n'importe quelle commande Bash. Si elle se termine avec succès, la première commande echo est exécutée ; dans le cas contraire, c'est la seconde qui est exécutée.
Famille C
Le code C suivant attribue result à la valeur de x si a > b, et, par ailleurs, d'une valeur de y. Cette syntaxe est identique à celle de nombreux langages apparentés, notamment le C++, Java, JavaScript et Dart.
result = a > b ? x : y;
Seule l'expression sélectionnée est évaluée. Dans cet exemple, x et y ne nécessitent aucune évaluation, mais peuvent être des expressions ayant des effets de bord. Seul l'effet de bord correspondant à la valeur de l'expression sélectionnée se produira[6],[7].
Si x et y sont du même type de données, l'expression conditionnelle est généralement de ce type. Sinon, les règles régissant le type de données résultant varient légèrement d'un langage à l'autre :
- En C++, les conversions de types arithmétiques habituelles sont effectuées pour convertir
xetyen un type commun. Si les deux sont des types de pointeur ou de référence, ou si l'un est un type de pointeur et l'autre une expression constante dont la valeur est 0, des conversions de pointeur ou de référence sont effectuées pour les convertir en un type commun[8]. - En C#, si une expression est implicitement convertible vers le type de l'autre, c'est ce type qui est utilisé. Dans le cas contraire, une erreur de compilation se produit[9].
- Dans les langages à typage dynamique, l'expression évaluée a le type de l'expression sélectionnée.
De plus, en C++, une expression conditionnelle peut être utilisée comme L-value (ru) si à la fois x et y sont des L-lvalues, même si cela est rarement utilisé dans la pratique [10]:
(foo ? bar : baz) = frink;
Common Lisp
Affectation à l'aide d'une expression conditionnelle en Common Lisp :
(setq result (if (> a b) x y))
Forme alternative :
(if (> a b)
(setq result x)
(setq result y))
dBASE
Dans dBase, la fonction conditionnelle iif(<expL>, <expT>, <expF>) s'appelle « Immediate IF ». Il utilise l'évaluation par raccourci (il n'évalue qu'une seule des <expT> ou <expF>).
Fortran
Dans le cadre de la norme Fortran 90, l'opérateur ternaire a été intégré à Fortran sous la forme d'une fonction intrinsèque merge :
variable = merge(x,y,a>b)
Notez que x et y sont tous deux évalués avant que la fonction ne renvoie l'un ou l'autre des résultats. Ici, x est renvoyé si la condition est vraie, et y dans le cas contraire.
Fortran-2023 a introduit des expressions conditionnelles qui évaluent l'une ou l'autre des expressions en fonction de l'expression conditionnelle :
variable = ( a > b ? x : y )
Kotlin
Kotlin ne propose pas la syntaxe de l'opérateur ternaire traditionnel ?:, cependant, if peut être utilisé comme une expression à laquelle on peut attribuer une valeur[11] et obtenir les mêmes résultats.
val max = if (a > b) a else b
Lua
Lua ne dispose pas d'un opérateur conditionnel classique. Cependant, le comportement de court-circuit des opérateurs and et or permet d'émuler ce comportement. Ce qui suit équivaut à : var = cond ? a : b.
var = cond and a or b
Cela fonctionnera, sauf si a est logiquement fausse ; dans ce cas, l'expression donnera toujours b. Si on ne tient pas compte de cela, cela peut entraîner des comportements inattendus.
Il existe également d'autres variantes, mais elles sont généralement plus longues :
var = (
{
[true] = a,
[false] = b
}
)[not not cond]
Luau, un dialecte de Lua, propose des expressions ternaires qui ressemblent à des instructions « if », mais contrairement à celles-ci, elles ne comportent aucun mot-clé end, et la clause else est requise. On peut, si on le souhaite, ajouter les clauses elseif. Il est conçu pour remplacer l'idiome cond and a or b et devrait fonctionner correctement dans tous les cas[12].
-- in Luau
var = if cond then a else b
-- with elseif clause
sign = if var < 0 then -1 elseif var == 0 then 0 else 1
Pascal
Pascal constituait à la fois une simplification et une extension d'Algol 60 (principalement pour la gestion des types définis par l'utilisateur). L'une de ces simplifications consistait à supprimer l'expression conditionnelle, car le même résultat pouvait être obtenu à l'aide de la forme moins concise de l'instruction conditionnelle.
RemObjects Oxygene (en) a ajouté un opérateur ternaire à Object Pascal vers 2011[13], et en 2025, Delphi a emboîté le pas[14]. Oxygene prend en charge les instructions case et switch, qui correspondent en substance à des boucles if répétées, ainsi que les expressions dont le résultat est une valeur[15].
Python
Un opérateur pour une expression conditionnelle en Python a été approuvé sous la forme Python Enhancement Proposal 308 et a été intégré à la version 2.5 en . L'opérateur conditionnel de Python diffère de l'opérateur commun ?: dans l'ordre de ses opérandes. La forme générale est la suivante[16]:
result = x if a > b else y
Cette forme invite à considérer x comme valeur normale et y à titre exceptionnel.
Rust
En tant que langage de programmation axé sur les expressions (de), la syntaxe de Rust if expr1 else expr2 peut fonctionner comme l'opérateur ternaire traditionnel ?: le fait. Les versions antérieures du langage comportaient bien l'opérateur ?: mais il a été supprimé[17] en raison d'un doublon avec if[18].
Remarquez l'absence de points-virgules dans le code ci-dessous, contrairement à un bloc plus déclaratif if...else, et le point-virgule à la fin de l'affectation à y.
let x = 5;
let y = if x == 5 {
10
} else {
15
};
On pourrait également écrire cela ainsi :
let y = if x == 5 { 10 } else { 15 };
Notez que les accolades sont obligatoires dans les expressions conditionnelles en Rust.
Vous pourriez également utiliser une expression match :
let y = match x {
5 => 10,
_ => 15,
};
Smalltalk
Chaque expression (envoi de message) a une valeur. Ainsi ifTrue:ifFalse: peut être utilisée :
|x y|
x := 5.
y := (x == 5) ifTrue:[10] ifFalse:[15].
SQL
L'expression SQL CASE est une généralisation de l'opérateur ternaire. Au lieu d'une condition et de deux résultats, il est possible de spécifier n conditions et n+1 résultats.
Avec une seule condition, cela revient (bien que de manière plus détaillée) à utiliser l'opérateur ternaire :
SELECT (CASE WHEN a > b THEN x ELSE y END) AS CONDITIONAL_EXAMPLE
FROM tab;
On peut étendre cela à plusieurs conditions :
SELECT (CASE WHEN a > b THEN x WHEN a < b THEN y ELSE z END) AS CONDITIONAL_EXAMPLE
FROM tab;
Visual Basic
Visual Basic fournit une fonction conditionnelle ternaire, IIf, comme le montre le code suivant :
Dim opening_time As Integer = IIf((day = SUNDAY), 12, 9)
Dans une fonction, les valeurs des trois arguments sont évaluées avant l'appel de la fonction. Pour éviter d'évaluer l'expression qui n'est pas sélectionnée, le mot-clé If a été ajouté (dans Visual Basic .NET 9.0) en tant que véritable opérateur conditionnel ternaire. Cela permet au code suivant d'éviter une exception s'il était implémenté avec IIf à la place :
Dim name As String = If(person Is Nothing, "", person.Name)
Voir aussi
- Disjonction conditionnée
- Multiplexeur
- Comparaison trilatérale
Références
- ↑ Christopher Strachey, « Fundamental Concepts in Programming Languages (en) », Higher-Order and Symbolic Computation (en), vol. 13, nos 1–2, , p. 11–49 (DOI 10.1023/A:1010000313106, S2CID 14124601)
- ↑ The BCPL Reference Manual, , 16–17 p. (lire en ligne [archive du ]), « 5.5 Conditional expressions »
- ↑ Eric Wastl, « Ternary operator associativity », sur phpsadness.com (consulté le )
- ↑ https://www.php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary
- ↑ « Rationale for Ada 2012 », sur ACAA (consulté le )
- ↑ ISO.IEC 9899:1999 (E) 6.5.15.4
- ↑ Java 7 Specification: 15.25 Conditional Operator ? :
- ↑ (en-US) Mike Blome, « Conditional Operator: ? », sur docs.microsoft.com (consulté le )
- ↑ (en-US) Bill Wagner, « ?: Operator - C# Reference », sur docs.microsoft.com (consulté le )
- ↑ « Conditional Operator », sur wiki.c2.com (consulté le )
- ↑ « Kotlin Lang If Expression », sur kotlinlang.org (consulté le )
- ↑ (en) « Syntax § If-then-else expressions », sur Luau (consulté le )
- ↑ « if then (else) expressions », sur DelphiTools (consulté le )
- ↑ « Coming in RAD Studio 13: A Conditional Ternary Operator for the Delphi Language », sur Embarcadero Blogs, (consulté le )
- ↑ « Texas, Start Your Photocopiers », sur RemObjects Blog (consulté le )
- ↑ « The Python Language Reference »
- ↑ « Remove Ternary Operator by pwoolcoc · Pull Request #1705 · rust-lang/Rust », sur GitHub
- ↑ « Remove ternary operator · Issue #1698 · rust-lang/Rust », sur GitHub
- Portail de la programmation informatique