Powershell: Suggestion : implémenter des conditionnels ternaires

Créé le 2 mars 2017  ·  52Commentaires  ·  Source: PowerShell/PowerShell

Les conditionnels ternaires de style C seraient un ajout pratique au langage.

Par exemple, au lieu d'écrire :

if ((get-date).tostring("ss") % 2) { 'odd'  } else  { 'even' }

on pourrait écrire :

(get-date).tostring("ss") % 2   ?   'odd'   :    'even'

Cela soulagerait également une déception de longue date :

Chez Microsoft, « expédier, c'est choisir ». L'une des choses que nous avons été très déçus de ne pas pouvoir livrer en V1.0 est un opérateur ternaire.

Extrait d'un article de blog de l'équipe PowerShell daté du 29 décembre 2006.


Connexe : mettre en œuvre des affectations null-coalescence et null-trempage et null-conditionnel

Committee-Reviewed Issue-Enhancement WG-Language

Commentaire le plus utile

@RichardSiddaway : Si nous examinons Stack Overflow sur les questions _postées depuis 2014_ par PowerShell, nous obtenons (au moment d'écrire ces lignes) :

$PSItem été introduit dans la v3 en septembre 2012, donc pour être sûr, j'ai choisi 2014 comme date de début pour la requête.

Bien que ce ne soit pas une métrique exacte, - le site ne vous permet malheureusement pas de rechercher $_ ou _ , et je suis sûr qu'il y a des questions qui contiennent _ni_ $_ ni $PSItem , et des questions pré-v3 sont toujours posées - je pense toujours qu'il est prudent de conclure que $_ est utilisé beaucoup plus fréquemment que $PSItem .

Cependant, le point le plus important est qu'il n'est pas nécessaire de _choisir_ :

Tout comme $PSItem et $_ coexistent avec bonheur, ainsi ForEach-Object et % , Where-Object et ? , .. .:

$a ? $b : $c peut coexister avec if ($a) { $b } else { $c } / $(if ($a) { $b } else { $c })

Quant à récapituler les raisons _positives_ d'introduire $a ? $b : $c

  • plus concis, moins encombré visuellement, utilisant une syntaxe familière à la plupart des programmeurs.

  • plus efficace, car il n'y a pas besoin de $(...) , dont les instructions if besoin pour permettre leur utilisation dans le cadre d'une expression plus large (qui est plus bruyante, moins efficace et peut avoir un côté inattendu effets)

Quant au souci d'obscurité :

Quelqu'un qui écrit des _expressions_ (par opposition à simplement _invoquer des commandes_ avec des arguments (simples)) peut être supposé avoir une certaine expérience de développeur, et mon sentiment (anecdotique) est que la plupart des développeurs au moins _reconnaît_ $a ? $b : $c comme un condensé if , qu'ils l'utilisent activement ou non.

Même s'ils ne le font pas, cependant, cela s'explique facilement, et à part l'utilisation de _symboles_ non évidents, la complexité conceptuelle est la même que celle d'un if ($a) { $b } else { $c } , et même inférieure à
$(if ($a) { $b } else { $c })

En supposant qu'il s'impose une fois introduit - certainement, cette discussion montre qu'il y a une demande pour cela - le rencontrer fréquemment en fera un idiome familier et facilement reconnaissable (c'est plus concis, plus facile à taper et, au moins pour moi et quelques autres ici, plus lisible) - tout comme la plupart des gens semblent préférer $_ à $PSItem .

Tous les 52 commentaires

Notez qu'avec la modification permettant d'autoriser les affectations à partir d'instructions, le besoin d'un opérateur ternaire est réduit. Vous pouvez simplement faire
$var = if ($x) { $x } else { $y }
Ce n'est pas aussi concis que l'opérateur ternaire, mais il est sans doute plus lisible.

Oui, mais vous devez toujours utiliser $(...) _en plus_ si le conditionnel fait partie d'une expression plus large :

'The current sec. is ' + $(if ((get-date).tostring("ss") % 2) { 'odd'  } else  { 'even' })

vs.

powershell 'The current sec. is ' + ((get-date).tostring("ss") % 2 ? 'odd' : 'even')

Je sais que la lisibilité est dans l'œil du ... euh ... lecteur, mais je trouve personnellement ce dernier visuellement plus facile à analyser, et avoir à taper moins est toujours un bonus.

Avec une fonctionnalité aussi fréquemment utilisée, je pense que se souvenir de la syntaxe ternaire plus abstraite ne serait pas un problème (et, bien sûr, les gens peuvent continuer à utiliser if , s'ils préfèrent).

@mklement0 Je dois convenir que plus tard a moins de charge cognitive.

C'est définitivement sur ma liste des meilleurs.
@BrucePay , y a-t-il des raisons pour lesquelles ce serait une mauvaise idée ? Ou s'agit-il simplement de « expédier, c'est choisir » ?

Dans le passé, cette demande de fonctionnalité a été refusée car elle était plus difficile à comprendre pour les scripteurs moins expérimentés, et que la forme d'expression de l'instruction if était une alternative plus claire, mais plus détaillée.

Mon point de vue personnel : si la langue n'était que pour moi, je l'aurais probablement ajoutée il y a longtemps. Mais ... je trouve que de nombreux développeurs ne l'utilisent pas, ce qui suggère en fait qu'il y a du vrai dans l'hypothèse selon laquelle les personnes moins expérimentées auront des problèmes avec l'opérateur ternaire.

@lzybkr :

Il vaut la peine de faire la distinction entre _l'utilisation active_ d'une fonctionnalité et la capacité de la _reconnaître_ et de la comprendre.

De toute évidence, tout le monde peut choisir d'utiliser une telle fonctionnalité, mais êtes-vous en train de dire que "avoir des problèmes avec" signifie que les personnes moins expérimentées ne la comprendront pas lorsqu'elles la verront dans le code des autres ?

@mklement0 - nous avons introduit $psitem comme alias pour $_ raison de suffisamment de retours indiquant que $_ était énigmatique et déroutant, donc je pense que l'opérateur ternaire serait difficile pour certains moins personnes expérimentées à comprendre.

D'un autre côté, de nombreux éléments dans PowerShell sont déroutants pour les débutants, voire pour les développeurs assez expérimentés.

Comme pour tout autre langage, il faut un certain effort pour apprendre la syntaxe et la signification des constructions linguistiques.
Je ne sais pas si je pense que l'opérateur ternaire est particulièrement difficile à saisir.

Avez-vous des données suggérant que c'est le cas ?

Je crois que les seules données sont anecdotiques, mais la critique s'applique à n'importe quel langage cryptique - bash, perl, etc.

Et pour être clair, je fournissais le contexte historique. Peut-être que PowerShell est suffisamment omniprésent maintenant qu'une syntaxe plus cryptique n'affectera pas l'adoption.

Gardez également à l'esprit que certains langages laconiques utilisent encore if/then comme opérateur ternaire, par exemple F#.

Cela dit, il est peut-être possible d'utiliser moins de caractères et de ne pas être trop cryptique :

if ($x) { $y } else { $z }
$x -then $y -else $z
$x ? $y : $z

-then/-else s'adapte bien à la syntaxe PowerShell - mais, un opérateur (ou des opérateurs si c'est trop déroutant pour être considéré comme un seul opérateur), vous avez l'avantage de ne pas avoir besoin de parenthèses ni d'accolades.

Là encore, cela demande des problèmes similaires à foreach vs foreach-object . mais peut-être que ce n'est pas si grave, je ne sais pas.

@lzybkr :

Cryptic à doses homéopathiques est sain :

PowerShell n'est globalement pas cryptique, mais offre dans certains cas une syntaxe cryptique comme _alternative_ concise (vous pouvez toujours être verbeux si vous le souhaitez) pour les constructions _fréquemment utilisées_, notamment ? pour Where-Object et % pour ForEach-Object .

Me proposer $x ? $y : $z comme alternative concise à if ($x) then { $y } else { $z } est dans le même esprit.

L'aspect énigmatique est amélioré par le fait que ? rappelle une _question_ et suggère donc un conditionnel (bien qu'un _précédant_ le ? dans ce cas), et - plus important - étant _une construction potentiellement familière de plusieurs d'autres langages_, avec la même sémantique fondamentale.

Vous n'obtenez pas le même avantage avec $x -then $y -else $z : ce n'est pas familier.

De plus, alors que de nombreux opérateurs PS ont des noms symboliques, beaucoup n'en ont pas : * / + % ...
Celles-ci sont également intrinsèquement cryptiques, nous ne les percevons tout simplement plus de cette façon, car elles sont si familières et omniprésentes.

Mon sentiment est que $x ? $y : $z aussi est déjà familier à beaucoup, et le deviendra encore plus une fois introduit dans le langage, étant donné le besoin fréquent de conditionnels concis.

Notez que vous serez assez limité dans ce que vous pouvez spécifier avec cet opérateur. En particulier, vous ne pourrez utiliser les commandes que si vous les placez entre parenthèses :

(test-path foo.txt) ? (get-content foo.txt) : (get-content bar.txt)

comparé à

if (test-path foo.txt) {get-content foo.txt} else {get-content bar.txt}

ou

get-content ((test-path foo.txt) ? "foo.txt" : "bar.txt")

vs

get-content $(if (test-path foo.txt) {"foo.txt"} else {"bar.txt"})

À mon avis, il y a peu d'avantage en termes de brièveté et un net inconvénient en termes de lisibilité. L'opérateur ternaire est beaucoup moins intéressant quand on a un langage orienté expression. Quand j'ai commencé sur le langage il y a 16 ans, l'ajout de l'opérateur ternaire m'a semblé évident venant d'un background C. Maintenant, je suis content que nous ne l'ayons jamais ajouté. Cela ressemble à du désordre.

En particulier, vous ne pourrez utiliser les commandes que si vous les placez entre parenthèses :

Cela s'applique à l'opérateur PowerShell _any_.

Toutes les instructions PowerShell n'impliquent pas de commandes, et lorsqu'elles le font, les utilisateurs savent déjà que (...) est le prix d'admission pour les commandes (dans la plupart des cas).

Dans votre propre exemple, pour moi, ((test-path foo.txt) ? "foo.txt" : "bar.txt") bat $(if (test-path foo.txt) {"foo.txt"} else {"bar.txt"}) , à la fois pour l'obscurité d'avoir besoin de $(...) et pour le bruit introduit par les accolades.

C'est peut-être juste moi mais je trouve ceci:

get-content ((test-path foo.txt) ? "foo.txt" : "bar.txt")

bien plus facile à numériser/analyser visuellement que ceci :

get-content $(if (test-path foo.txt) {"foo.txt"} else {"bar.txt"})

Ma seule plainte à propos de ce problème est que si vous allez faire ternaire ?: alors vous devriez également faire une fusion nulle ?? :

$logDir = $env:LogDir ?? "$PSScriptRoot\Log"

J'ai vu un certain nombre d'implémentations Invoke-Ternary et Invoke-NullCoalescing dans la nature (par exemple https://github.com/dahlbyk/posh-git/blob/master/src/Utils.ps1#L12). Cela indique en quelque sorte qu'il existe un désir général pour une telle fonctionnalité intégrée dans la langue.

@rkeithhill : je suis d'accord ; re null-coalescing : il y a déjà un problème, qui couvre également le null-trempage : #3240

Ainsi, l'argument des codeurs moins expérimentés ne serait pas en mesure d'utiliser facilement une instruction de code à fusion nulle ou ternaire, je pense que c'est un peu myope. Il n'y a aucune obligation d'utiliser ces fonctionnalités "avancées" et si un programmeur ne peut pas lire le code parce qu'il manque d'expérience, alors personnellement, c'est mon signal que j'ai besoin d'apprendre quelque chose de nouveau très rapidement.
Quand j'ai vu pour la première fois un ternaire en C #, j'étais comme WTF est ce nouvel enfer que MS a introduit, jusqu'à ce que je prenne quelques minutes pour lire à ce sujet, ce qui m'a alors accroché.

Exemple pratique dans POSH, j'ai cette ligne :
$mc_object = ($Message.fields | where Name -Match appname).Content
ce qui est très bien, sauf lorsque l'objet $Message n'a pas de propriété classée portant le nom de "nom d'application", et comme je ne contrôle pas les données au format JSON dont elles proviennent, je dois déterminer quoi faire.

Ainsi, avec une opération de fusion nulle, tout ce que j'ai à faire est d'ajouter ?? "" à la fin pour m'assurer que le $mc_object était toujours une chaîne valide, même si le setter d'origine était nul. Sinon, je devrais utiliser différentes techniques pour accomplir ce que 4 frappes peuvent faire, telles que
$mc_object = if(-not ($Message.fields | where Name -Match appname).Content)){""}else{($Message.fields | where Name -Match appname).Content}
Pour moi, c'est très illisible, mais je peux ensuite nettoyer un peu en faisant quelque chose comme ça, ce que je fais.
$mc_object = ($Message.fields | where Name -Match appname).Content if(-not $mc_object){$mc_object = ""}

Bien que ce ne soit pas terrible, c'est bien plus que 4 touches pressées pour null-coelasce.

Quoi qu'il en soit, je vote définitivement pour le ternaire et le null-coelasce dans Powershell, cela ajoute des fonctionnalités très avancées et rend simplement Powershell plus attrayant à utiliser sous la forme "noyau" sur n'importe quel système.

@lzybkr Je n'ai encore vu personne adopter $PSItem . Je travaille dans une équipe assez nombreuse de personnes qui écrivent des scripts et elles utilisent toujours $_ , même les utilisateurs de PowerShell les moins expérimentés.

@tibmeister ou....

if (-not ($mc_object = $Message.fields.where{$_.Name -match 'appname'}.Content)) {
    $mc_object = ''
}

Les affectations en tant qu'expressions passeront, mais sont incroyablement illisibles.

J'utilise régulièrement $psitem

Au cours de plusieurs années de jugement sur les jeux de script, $psitem a été beaucoup utilisé dans les réponses.

@RichardSiddaway : Si nous examinons Stack Overflow sur les questions _postées depuis 2014_ par PowerShell, nous obtenons (au moment d'écrire ces lignes) :

$PSItem été introduit dans la v3 en septembre 2012, donc pour être sûr, j'ai choisi 2014 comme date de début pour la requête.

Bien que ce ne soit pas une métrique exacte, - le site ne vous permet malheureusement pas de rechercher $_ ou _ , et je suis sûr qu'il y a des questions qui contiennent _ni_ $_ ni $PSItem , et des questions pré-v3 sont toujours posées - je pense toujours qu'il est prudent de conclure que $_ est utilisé beaucoup plus fréquemment que $PSItem .

Cependant, le point le plus important est qu'il n'est pas nécessaire de _choisir_ :

Tout comme $PSItem et $_ coexistent avec bonheur, ainsi ForEach-Object et % , Where-Object et ? , .. .:

$a ? $b : $c peut coexister avec if ($a) { $b } else { $c } / $(if ($a) { $b } else { $c })

Quant à récapituler les raisons _positives_ d'introduire $a ? $b : $c

  • plus concis, moins encombré visuellement, utilisant une syntaxe familière à la plupart des programmeurs.

  • plus efficace, car il n'y a pas besoin de $(...) , dont les instructions if besoin pour permettre leur utilisation dans le cadre d'une expression plus large (qui est plus bruyante, moins efficace et peut avoir un côté inattendu effets)

Quant au souci d'obscurité :

Quelqu'un qui écrit des _expressions_ (par opposition à simplement _invoquer des commandes_ avec des arguments (simples)) peut être supposé avoir une certaine expérience de développeur, et mon sentiment (anecdotique) est que la plupart des développeurs au moins _reconnaît_ $a ? $b : $c comme un condensé if , qu'ils l'utilisent activement ou non.

Même s'ils ne le font pas, cependant, cela s'explique facilement, et à part l'utilisation de _symboles_ non évidents, la complexité conceptuelle est la même que celle d'un if ($a) { $b } else { $c } , et même inférieure à
$(if ($a) { $b } else { $c })

En supposant qu'il s'impose une fois introduit - certainement, cette discussion montre qu'il y a une demande pour cela - le rencontrer fréquemment en fera un idiome familier et facilement reconnaissable (c'est plus concis, plus facile à taper et, au moins pour moi et quelques autres ici, plus lisible) - tout comme la plupart des gens semblent préférer $_ à $PSItem .

mklement0, vous avez un exemple très impressionnant et je pense que cela démontre clairement le point, merci.

En relisant et en revisitant cela et en examinant certaines des questions, je me retrouve à pencher davantage vers les syntaxes légèrement plus verbeuses suggérées :

$value = $a -eq $b -then $trueVal -else $falseval

ou, pour une syntaxe plus sémantiquement lisible :

$value = $trueVal -if $a -eq $b -else $falseVal

@ vexx32 Bien que votre premier exemple ne me dérange pas, je trouve la condition au milieu d'une expression extrêmement lourde.

Oui, je pense que je suis d'accord, mais il ne sait ni lire un peu plus ... en douceur. Mais j'aurais toujours tendance à aller au premier.

Étant donné que PowerShell est destiné à être un langage "en rampe" vers C#, je pense que l'utilisation de ? : est la voie à suivre. Même JavaScript utilise cette syntaxe et c'est l'un des langages les plus populaires de nos jours. :-)

D'accord, @rkeithhill , à la fois pour la familiarité de la construction de plusieurs autres langages _et_ le désir d'avoir également des affectations null-coalescing, null-soaking et null-conditional , qui en C# sont également basées sur ? .

Les deux derniers - par exemple $foo?.bar et $var ?= 'default val' - ne sont pas vraiment possibles sans une représentation basée sur des symboles, et même pour la fusion nulle, $a ?? 'value-if-null' semble préférable à quelque chose comme $a -elseifnull 'value-if-null' .

N'oubliez pas que ? , en tant qu'alias fréquemment utilisé pour Where-Object , est déjà fermement établi comme représentant un _conditionnel_, donc le transfert de cette connaissance vers des variantes de son utilisation semble logique.

PowerShell est-il vraiment une rampe d'accès à C# ? Je sais que c'était une intention déclarée il y a 10 à 12 ans, mais est-ce vraiment en train de se produire ? Je soupçonne que pour la majorité des utilisateurs de PowerShell, C# n'est pas un endroit où ils veulent aller.

si des conditionnels ternaires doivent se produire, je préférerais voir quelque chose comme
$value = $trueVal -if $a -eq $b -else $falseVal

comme mentionné par @vexx32

Cela a plus de sens pour l'utilisateur moyen de PowerShell.

@mklement0 Mes commentaires sur $psitem étaient basés sur mon expérience personnelle. Si vous avez eu une expérience différente, cela n'invalide pas mon expérience

je sais que c'était une intention déclarée il y a 10-12 ans

Oui, aux premiers sommets des MVP, entre autres, par Jeffrey. Je n'ai pas entendu de différence depuis lors.

De plus, presque toutes les constructions conditionnelles/boucles proviennent de C# (et de la lignée C), if {} , while {} , do {} while , switch {} , for {} , foreach {} , essayez {} catch {} finally {}`. Il me semble logique que cette construction conditionnelle le soit aussi.

Ce sont des mots-clés de langue, cependant, @rkeithhill. Les opérateurs sont totalement différents.

Je pense que vous constaterez que la grande majorité des opérateurs utilisés dans PowerShell sont assez différents de leurs équivalents C#. L'équipe PS a très clairement opté pour une syntaxe plus descriptive pour la majorité des opérateurs.

Je considérerais que le comportement ternaire devrait également suivre les options de syntaxe plus détaillées disponibles. PowerShell a peut-être été conçu comme une " rampe d'accès " vers C #, mais cela ne signifie pas qu'il devrait hériter de ses syntaxes plus symboliques. En effet, il existe de nombreux endroits où cela a été soigneusement évité .

Considérez, si vous le voulez bien, que vos arguments pour la syntaxe symbolique sont enracinés dans la façon dont d'autres langages de programmation courants représentent ce concept. PowerShell n'a pas été du genre à suivre cette voie dans la publication, préférant plutôt travailler avec une syntaxe aussi descriptive que possible. Le simple fait que les utilisateurs qui ont déjà une expérience en C# connaissent une telle syntaxe n'est assurément pas une raison pour l'utiliser.

Si PowerShell est un langage "d'accès rapide" à C # ou à tout autre langage (ce qui, je pense, il se débrouille assez bien jusqu'à présent), nous devons alors considérer le plus petit dénominateur commun ici et réfléchir à ce que les personnes les plus inexpérimentées trouveraient sensible et intuitif .

Je ne dis pas que mes solutions sont proférées, mais je pense qu'ils sont probablement dirigés dans une direction plus sensible dans cette perspective.

@vexx32
Et ces opérateurs ?

.
=
[]
,
+ - * / %
++ --
+=  -=  *=  /= %=

En règle générale, je suis d'accord pour dire que suivre l'exemple de C# n'est pas toujours approprié et que la préservation de l'esprit de PowerShell doit primer.

À l'inverse, je déconseille de s'écarter de C# dans les cas où la même syntaxe semble être un ajustement plausible, et pour moi la proposition à l'étude - avec #3240 - en est un exemple.

Si on laisse de côté les autres langues :

  • La sémantique actuelle de ? s'étend de manière plausible aux opérateurs proposés.

  • Si vous voyez une valeur dans les opérateurs _related_ proposés - null-trempage ( ?. ), null-coalescing ( ?? ) et affectation conditionnelle null ( ?= ) - alors optez pour une forme ternaire verbeuse telle que -then / -else n'est pas une option, si vous voulez que tous ces opérateurs liés reflètent un point commun (qu'ils ont évidemment conceptuellement).

Plus une fonctionnalité est exotique, plus la verbosité est importante.

Plus une fonctionnalité est utilisée fréquemment, plus la concision est importante. Et l'abstraction d'une représentation basée sur des symboles cesse d'être un problème grâce à une simple exposition répétée à la syntaxe - tout comme avec * , par exemple.

Tous les opérateurs dont je parle entrent dans cette dernière catégorie.


@RichardSiddaway :

Mes commentaires sur $psitem étaient basés sur mon expérience personnelle. Si vous avez eu une expérience différente, cela n'invalide pas mon expérience

Oui, vos commentaires étaient basés sur une expérience _personnelle_.
Les miennes étaient basées sur _l'analyse des données_ du populaire site de questions-réponses Stack Overflow, pour en déduire des modèles d'utilisation _généraux_ (dans les limites des contraintes énoncées) - ce qui n'a rien à voir avec mon expérience personnelle.

La seule raison pour laquelle vous pourriez percevoir mes commentaires comme invalidant les vôtres si vous pensez que vos observations personnelles reflètent une vérité "transpersonnelle" - une affirmation que vous n'avez pas faite en tant que telle dans vos commentaires. Vouliez-vous le faire? Si c'est le cas, nous devons discuter de _ce_.

Presque tous ces opérateurs sont des opérateurs mathématiques avec une signification relativement claire, @mklement0 😄

Un opérateur ternaire est un opérateur conditionnel , et _tous_ les opérateurs booléens/conditionnels de PS sont de la forme la plus détaillée : -and , -or , -eq , -ne , -contains , etc.

Cependant, je conviens que ce raccourci peut avoir du sens en raison du besoin des fonctionnalités environnantes et des opérateurs associés. Mais je pense que la syntaxe ternaire "standard" n'est pas particulièrement intuitive pour ceux d'entre nous qui n'y ont

les opérateurs sont des opérateurs mathématiques

Parmi ceux répertoriés, seuls + - * / % ont une signification (purement) mathématique, mais l'aspect bien compris s'applique également aux autres (à l'exception de = , étant donné qu'il est souvent confondu avec les tests d'égalité ).

La meilleure construction pour comparer <condition> ? <if-true> : <else> est la if _statement_, pas les autres opérateurs. Alors que if est certainement plus verbeux, c'est précisément cet aspect que l'opération ternaire est censée traiter (en plus d'être une expression vraie et composable, contrairement à if ).

Il existe un spectre de concision, bien sûr, mais, comme vous le dites, pour s'adapter à tous les opérateurs connexes proposés de manière cohérente, une syntaxe basée sur des symboles est logique.

à ceux d'entre nous qui n'y ont pas déjà été exposés à plusieurs reprises.

Eh bien, j'espère que cela changera bientôt. ??
Point pris, mais (a) la syntaxe est facile à expliquer et a la même complexité conceptuelle qu'une déclaration if , et (b) une exposition répétée devrait aider à la rétention de la mémoire.

@mklement0 Comment ? soit un caractère de nom valide ? Changement de rupture ? Je considère que les gens sur powershell core connaissent bien powershell tel qu'il est et que la syntaxe supplémentaire (qui existe dans d'autres langages depuis près de 50 ans) ne sera pas un obstacle. Ils peuvent toujours utiliser if/else s'ils veulent plus de verbosité.

? n'est qu'un alias valide en mode commande ; dans toutes les variantes du mode d' expression , il s'agit simplement d'un caractère invalide à l'heure actuelle. Il n'y a pas de collision.

Si vous essayez d'entrer ce code, il produira simplement une erreur :

$Value = $true
$Value ? "Hello!" : "Goodbye!"

Résultat:

At line:1 char:8
+ $Value ? "Hello!" : "Goodbye!"
+        ~
Unexpected token '?' in expression or statement.
+ CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken

@vexx32

$what? # <- example of a valid variable name

Dans son exemple de trempage nul : $var?.maybenull() ne se soucie pas du fait qu'il y ait un point d'interrogation et si quelqu'un essaie d'être trop condensé, son ternaire se brisera.

Désolé, cela a été principalement discuté dans l'autre question à ce sujet, donc je ne pensais pas que vous faisiez référence à cela.

Que nous puissions ou non empêcher que ce soit un caractère de nom de variable valide dépend de l'équipe PS, mais je suis enclin à être d'avis qu'empêcher qu'il soit considéré comme un caractère de nom de variable par défaut ne casserait pas grand-chose. Je ne pense pas avoir jamais vu quelqu'un utiliser réellement ? dans le cadre d'un nom de variable.

@vexx32 Ouais, je devrais en

$var = $test?$thing1:$thing2

mais je coupe peut-être trop les cheveux en quatre pour ceux d'entre nous qui vivent dans la coquille.

Corrigée:

$var = ${test}?${thing1}:$thing2

@mklement0 - Je ne suis pas nécessairement d'accord avec :

La meilleure construction pour comparer?:to est l'instruction if, pas les autres opérateurs. Alors que if est nettement plus verbeux, c'est précisément cet aspect que l'opération ternaire est censée aborder (en plus d'être une expression vraie et composable, contrairement à if).

Plus précisément, l'opérateur ternaire existe parce que C/C# sont des langages orientés instructions mais qui nécessitaient des expressions conditionnelles.

Dans les langages orientés expression (par exemple F# ou Rust), il n'y a pas de syntaxe laconique car elle est considérée comme inutile. Je pense que cette vieille discussion sur la suppression de l'opérateur ternaire par Rust est intéressante.

Une chose que j'aime vraiment dans Rust est l'utilisation de l'opérateur ? pour la gestion des erreurs. Je n'ai pas de proposition concrète pour utiliser ? dans PowerShell, mais il me semble que ? pourrait être mieux utilisé pour la gestion des erreurs que pour une expression conditionnelle.

@TheIncorrigible1 , @vexx32 : Oui, le trempage nul serait techniquement un changement décisif , mais espérons-le de type bucket 3 (en effet, poursuivons la discussion là-bas); pour l'opération ternaire, l'utilisation suggérée de {...} / whitespace avant ? pour la désambiguïsation semble résoudre ce problème.

@lzybkr :

Plus précisément, l'opérateur ternaire existe parce que C/C# sont des langages orientés instructions mais qui nécessitaient des expressions conditionnelles.

Eh bien, dans PowerShell, les instructions de contrôle de flux telles que if sont des _half_-expressions ; dans les expressions _simples_, l'opération ternaire proposée serait équivalente ; dans les imbriqués, cela ne serait pas :

$foo = $True  ?     1   :      0    # proposed ternary
$foo = if ($True) { 1 } else { 0 }  # equivalent `if` statement
$foo = 1 + ($True  ?     1   :      0)   # nesting OK; note that + would have higher precedence
$foo = 1 + if ($True) { 1 } else { 0 }  # !! doesn't work
$foo = 1 + (if ($True) { 1 } else { 0 })  # !! doesn't work, even with parentheses
$foo = 1 + $(if ($True) { 1 } else { 0 })  # only $(...) (and situationally @(...)) work

Le besoin de $() / @() est plus qu'un simple inconvénient de syntaxe : il a des implications comportementales et de performance.

Cela dit, je _souhaite_ que les déclarations telles que if et foreach soient des expressions de bonne foi (deux autres exemples de choses qui échouent actuellement : foreach ($i in 1..5) { $i } | Write-Output ou foreach ($i in 1..5) { $i } > out.txt ).
Je n'en sais pas assez pour juger s'ils _ne peuvent pas l'être_, cependant et/ou s'il y a un problème de compatibilité descendante.
Voir aussi : #6817


Si if devenait une expression complète dans PowerShell, alors vous pourriez faire valoir l'argument qui a conduit à la suppression du conditionnel ternaire de Rust : il n'est alors plus _nécessaire_.

Cependant, ma motivation pour cette proposition n'a jamais été la _nécessité_ - c'est une question de concision, de commodité et de lisibilité (encombrement visuel).


Je n'ai pas de proposition concrète à utiliser ? dans PowerShell, mais on dirait ? pourrait être mieux utilisé pour la gestion des erreurs que pour une expression conditionnelle.

Je pense qu'introduire ? avec une sémantique fondamentalement différente de celle du C# serait une source de confusion éternelle.

Séparément, les améliorations de la gestion des erreurs de PowerShell méritent d'être discutées.

Si nous recherchons une alternative concise mais peu intuitive à If/Then/Else, nous en avons déjà une.

( 'False', 'True' )[( Test-Condition )]

Et ça marche dans les expressions.

"This statement is " + ( 'False', 'True' )[( Test-Condition )]

@TimCurwick : C'est concis (et plus obscur), mais pas équivalent : le conditionnel ternaire proposé serait _court-circuiter_ (tout comme une instruction if ), alors que votre syntaxe évalue invariablement les _deux_ alternatives.

Cela dit, votre syntaxe est certainement la meilleure chose disponible actuellement, en supposant que l'on soit conscient de la limitation indiquée.

Concernant la discussion sur la façon d'afficher les choix ternaires dans PowerShell, quelqu'un a-t-il envisagé une option dans le même format que celui utilisé par -replace / .replace() ?

$a -eq $b -ternary $a,$c
$true -ternary 1,0

ou

($a -eq $b).ternary($a,$c)
($true).ternary(1,0)

Cela indiquerait clairement que l'opérateur effectue une action ternaire en l'appelant littéralement ternaire . C'est verbeux, mais toujours court à écrire, et il utilise le comportement commun existant de -operator $first,$second , il devrait donc sembler familier aux utilisateurs de powershell dans toutes les gammes d'expérience

🤔 cela pourrait fonctionner, mais ce serait plus gênant que n'importe laquelle des alternatives proposées. -replace fonctionne de cette façon car il accepte simplement un tableau réel d'arguments. .Replace() n'est pas géré par l'équipe PS -- c'est une méthode sur la classe .NET System.String .

Si nous devions essayer d'utiliser l'une de ces syntaxes, cela signifierait soit une méthode ETS (ce qui est correct, mais a tendance à ajouter un peu de surcharge de performances à la création d'objets auxquels elle doit être attachée) ou, avec la version de l'opérateur vous proposez, nous ne serions pas en mesure d'avoir facilement un tableau comme argument.

Sans boîtier spécial d'un tel opérateur dans l'analyseur, nous ne serions pas en mesure de court-circuiter. Les syntaxes ternaires dans d'autres langages existent généralement parce que vous _ne voulez pas_ évaluer réellement les deux options ; le temps de calcul est plus rapide si seule la branche correcte doit être évaluée, plutôt que d'avoir à évaluer complètement les deux options (ce qui peut entraîner des effets secondaires importants).

Et puisque cela nécessiterait déjà une casse spéciale, il serait plus efficace d'introduire une nouvelle syntaxe pour cela, pour minimiser la confusion (ce serait un peu trompeur d'avoir quelque chose qui ressemble à un tableau mais qui ne peut pas être utilisé comme tel ; il ne prendrait pas en charge la création du "tableau" à l'avance et le passage en tant que variable, par exemple). Le fait que les arguments de méthode entrent déjà un peu en conflit avec la syntaxe du tableau est souvent déjà trompeur. Je ne pense pas que je voudrais ajouter un comportement de _troisième_ variante pour les virgules au mélange.

@PowerShell/powershell-committee en a longuement discuté, nous ne sommes pas tous d'accord, mais une majorité convient qu'il est utile d'avoir cet opérateur et de s'aligner sur la syntaxe C# en gardant ?: comme attente est que la plupart des utilisations seront être des développeurs C#. Cette fonctionnalité sera expérimentale dans l'attente d'un retour d'utilisation réel.

@SteveL-MSFT Cela signifie-t-il que la fonctionnalité avance pour la version 7.0 ? Cela brisera-t-il la compatibilité sur les variables pouvant utiliser ? dans leur symbole ?

@TheIncorrigible1 oui, cette fonctionnalité progresse dans PS7. Cela ne devrait pas rompre la compatibilité avec l'utilisation de l'alias ? . Il y a une inquiétude concernant l'acuité visuelle de ? lorsque l'on regarde un script essayant de différencier Where-Object et ternary , mais nous verrons quels sont les commentaires des utilisateurs à ce sujet. En général, nous ne nous attendons pas à ce que la plupart des utilisateurs utilisent cet opérateur mais cela ne devrait pas l'empêcher d'avancer.

@SteveL-MSFT Je veux dire des variables avec un nom de $isValid? ou similaire. Ce sont des jetons valides dans l'itération actuelle de PS.

@L'Incorrigible1 :

Exiger un espace entre le premier opérande et le ? résout ce problème, comme suggéré précédemment, et pour moi c'est une solution parfaitement raisonnable :

  • Le : _également_ nécessite des espaces autour, car quelque chose comme $true ? $number:42 ne fonctionnerait pas, étant donné que $number:42 serait _dans son ensemble_ interprété comme une référence de variable unique.

  • Bien que C# _autorise_ true?number:42 , je ne pense pas que nous ayons besoin - ou, en fait, que nous puissions - nous inquiéter de la compatibilité à ce niveau. Personnellement, j'apprécie la concision, mais pas au détriment de la lisibilité ; même si je _pouvais_ écrire $true?$number:42 , je ne le ferais pas.

(La compatibilité descendante sera en effet un problème lorsque (indice, indice) nous implémentons un accès conditionnel nul . La permissivité de PowerShell en ce qui concerne les noms d'identifiant est généralement problématique, comme @KirkMunro l' a récemment soutenu, mais ce navire a navigué )

Oui, je pense qu'il est judicieux de laisser l'exigence d'espace blanc. C'est assez laconique comme ça, après tout. ??

Le prototype a essayé assez fort d'analyser différemment les nombres contenant ? et : dans le contexte de l'opérateur ternaire (où nous savons que nous attendons une expression). Vous pouvez donc écrire des choses comme ${isWindows}?12:47 .
Des nombres comme 123? ou 1:23 sont tokenisés comme un jeton générique aujourd'hui, ce qui n'est pas du tout utile dans le cas où nous savons que nous attendons une expression.

Pour les variables, aucun changement sur la façon dont ? ou : peuvent être utilisés pour le nom de la variable, puisque la variable est une expression.

Bon point, @daxian-dbw; J'ai oublié que {...} peut être utilisé pour résoudre toute ambiguïté de limite de nom de variable, donc je suppose que les golfeurs de code pourraient utiliser quelque chose comme ${isWindows}?${number}:47

Pouvons-nous fermer cela maintenant?

Fermer via #10367

Cette page vous a été utile?
0 / 5 - 0 notes