Powershell: Ne nécessite pas { ... } autour des noms de variables pour l'accès aux membres conditionnels null

Créé le 17 déc. 2019  ·  53Commentaires  ·  Source: PowerShell/PowerShell

Suivi de #3240.

L'accès membre conditionnel ( ?. ) a été implémenté et sera disponible en tant que fonctionnalité _expérimentale_ dans la version 7.0

Cependant, dans l'intérêt de la compatibilité descendante, la mise en œuvre nécessite actuellement que le nom de la variable soit entouré de {...} , car ? est techniquement un caractère légal dans un nom de variable dont l'utilisation étonnamment _ne nécessite pas_ {...} .

C'est-à-dire que si vous souhaitez ignorer une tentative d'appel de $obj.Method() si $obj est $null (ou indéfini), vous vous attendez à ce qui suit, analogue à C# :

# Does NOT work as intended.
# 'obj?' as a whole is interpreted as the variable name.
$obj?.Method()

Au lieu de cela, vous devez actuellement utiliser :

# !! Must enclose 'obj' in {...} to signal that '?' is a syntactic element as part of '?.'
${obj}?.Method()

_Mise à jour_ : Null-coalescing - $var??='default et $a??$b - et l'opérateur ternaire - $var?1:0 - sont affectés de la même manière (bien qu'il y ait l'utilisation d'espaces avant le ? résout le problème).

Cette exigence est (a) inattendue et (b) lourde :

  • Les nouveaux utilisateurs ne s'attendront pas à avoir besoin de {...} et ne sauront pas nécessairement que _c'est ce qui est requis lorsque ce qui suit échoue (peut-être _non détecté_, à moins que Set-StrictMode -Version 2 ou plus ne soit en vigueur) : $o = [pscustomobject] @{ one = 1 }; $o?.one

  • Même une fois que les utilisateurs connaissent le besoin de {...} :

    • Ils oublieront de l'utiliser à l'occasion, à cause de son besoin contre-intuitif.
    • Lorsqu'ils s'en souviendront, cette exigence apparemment artificielle sera une source permanente de frustration, d'autant plus que {...} est difficile à saisir.

L'utilisation de {...} ne devrait pas être nécessaire, et bien que ne l'exigeant pas, cela équivaut à un changement _de rupture_, il tombe sans doute dans le seau 3 : Zone grise improbable .


Pourquoi ce changement devrait être considéré comme acceptable :

Remarque : @rjmholt explique pourquoi la modification de la syntaxe de PowerShell est très problématique _en général_ dans ce commentaire , mais pour les raisons présentées ci-dessous, je pense qu'il vaut la peine de faire une exception ici.

?. est une _nouvelle_ fonctionnalité syntaxique ; par définition, les scripts qui l'utilisent _ne peuvent pas_ (significativement) s'exécuter sur les anciennes versions - à moins que vous n'ajoutiez spécifiquement des conditions qui fournissent des chemins de code compatibles avec les versions héritées, mais cela ne semble guère en valoir la peine - vous vous en tiendrez alors simplement aux fonctionnalités héritées.

Oui, l'interprétation de $var?.foo dans les anciens scripts qui utilisaient $var? comme nom de variable ne fonctionnerait pas, mais :

  • ? n'aurait jamais dû être autorisé dans le cadre d'un identifiant _sans l'entourer de {...} _.

  • Étant donné que pouvoir le faire est inattendu et probablement même _inconnu_ pour beaucoup, de tels noms variables sont extrêmement rares dans la nature, d'après l'expérience personnelle, mais l'analyse de @mburszley fournit des preuves plus tangibles .

    • Même Ruby n'autorise que ? (et ! ) à la _fin_ des identifiants, et il n'y a que des identifiants _method_, et je soupçonne que la plupart des utilisateurs de Ruby savent qu'ils ne devraient _pas_ supposer que d'autres langues prennent en charge la même chose.

Donc, de façon pragmatique :

  • La grande majorité du code existant ne sera pas affectée - un jeton tel que $var?.foo ne sera tout simplement pas rencontré.

  • Si vous écrivez $var?.foo avec la nouvelle sémantique, alors oui, l'exécuter sur des versions plus anciennes pourrait entraîner un comportement différent (plutôt que de casser de manière évidente), selon le mode strict en vigueur - mais _vous devriez toujours appliquer la version minimale requise pour exécuter votre code comme prévu de toute façon_ ( #requires -Version , clés de manifeste de module).

Dans l'ensemble, pour moi, il s'agit d'un cas clair de changement de seau 3: un changement techniquement révolutionnaire qui casse très peu de code existant tout en offrant de réels avantages (ou, à l'inverse, évitant les maux de tête permanents dus à un comportement inattendu).

Committee-Reviewed Issue-Enhancement WG-Language

Commentaire le plus utile

@rjmholt , bien que je pense que nous pouvons tous comprendre à quel point un changement comme celui-ci est délicat _en principe_, dans ce cas particulier, cela n'a pas d'importance _en pratique_, et je ne pense pas qu'une règle PSSA soit même nécessaire :

  • L'analyse de @ThomasNieto a montré que - si nous pensons que le corpus est représentatif de tout le code PowerShell existant - que _pratiquement personne n'utilise de variables dont les noms se terminent par ? _.

  • Si je devais deviner, la plupart des gens ne penseraient même pas à utiliser de tels noms de variables, car ils ne s'attendraient pas à ce qu'ils fonctionnent (moi inclus), et ne remarqueraient probablement même pas l'exception selon laquelle le $? automatique $? constitue (dont le nom est également une exception dans les shells compatibles POSIX tels que bash ).

    • En fait, un examen plus attentif de l'analyse de 8 répertoriés :

      • 5 ne contiennent que des _faux positifs_, à savoir des variables utilisées à l'intérieur de _chaînes_ telles que "Are you sure you want to kill $vParam?" - en fait, ces utilisations sont _cassées_, et révèlent que les auteurs du script _pas_ s'attendaient ? ce que

      • 2 de ces fichiers ne sont plus accessibles au public.

      • Seuls _1_ d'entre eux sont une utilisation de bonne foi des variables de terminaison $key1? ), qui, en passant, ne sont donc _pas_ combinées avec l'opérateur d'accès aux membres , . /cc @stevenayers.

Sur la base de ce qui précède, cela me semble être un manuel Bucket 3: Improbable Gray Area change, qui est donc _acceptable_ - et je pense que les _avantages_ de ce changement ont été argumentés de manière convaincante.

_Documenter_ le changement de comportement (avec une justification) devrait suffire.

Bien sûr:

  1. ceci est fondé sur (a) que l'analyse soit correcte et (b) que le corpus accessible au public soit représentatif.

  2. c'est tout à fait en contradiction avec l'affirmation du comité selon laquelle "il y avait beaucoup d'utilisation de noms de variables se terminant par le point d'interrogation" (ce qui, bien sûr, ne serait un problème que si de tels noms de variables ne sont pas inclus dans {...} ).

En partant du principe que 1. est vrai (nous n'avons rien entendu à l'appui de 2.), nous avons deux options :

  • Déchirez le pansement et interdisez simplement ? dans les noms de variables à l'avenir, à moins qu'il ne soit inclus dans {...} (à l'exception évidente de $? ) - cela brisera le minuscule proportion de scripts qui reposent actuellement sur cela.

    • C'est-à-dire quelque chose comme $key1? qui n'est suivi ni de . ni d'un autre ? ( $key1??'else' ) ni d'une expression ternaire ( $key1?1:0 ) provoquerait une _erreur d'analyseur_.

      • Comme le montrent les exemples de fusion nulle et d'opérateur ternaire, eux aussi bénéficieraient de ce changement - actuellement, vous avez soit besoin d'un _space_ - $key1 ?1:0 / $key1 ??'else' - ou {...} - ${key1}?1:0 / ${key1}??'else'

    • À l'intérieur des _chaînes extensibles_, ? ne seraient plus considérés comme faisant partie d'un nom de variable (non inclus dans {...} ), donc nous _réparerions_ les scripts existants qui ont utilisé par erreur des chaînes telles que "Are you sure you want to kill $vParam?" . ??
  • Si nous pensons vraiment que nous devons éviter de casser la proportion infime de scripts existants, nous _pourrions_ considérer la logique proposée par @ExE-Boss , mais je ne pense pas que nous voulions introduire cette complexité conceptuelle - et encore moins la complexité d'implémentation (que j'ai je ne peux pas vraiment parler).

Tous les 53 commentaires

Pour clarifier, le jalon signifie simplement que c'est quelque chose dont l'équipe doit discuter en fonction des commentaires, et non que nous nous engageons à apporter ce changement.

@mklement0

? n'aurait jamais dû être autorisé dans le cadre d'un identifiant sans le mettre entre {...}.

Ummm - le langage de base initial pour PowerShell était le Posix Shell qui utilise $? pour le code de sortie qed '?' est autorisé dans les noms de variables sans guillemets.

il ne peut pas (significativement) fonctionner sur les anciennes versions

Bien sûr, il peut :

PS>  $abc?=@{a=1; b=2; c=3}
PS>  $abc?.b                                                                                        1
PS>  2                      

Bien sûr, il peut :

Il ne peut pas fonctionner de manière significative _avec la nouvelle sémantique_ (accès conditionnel nul) - c'est tout ce que je voulais dire.

Oui, votre exemple fonctionne actuellement, mais _avec une sémantique différente_ ( abc? _y compris le ? _ étant considéré comme le nom de la variable) - mais pour les raisons indiquées, ce cas de coin mérite d'être abandonné pour le plaisir de faire ?. fonctionne comme prévu.

Le langage de base initial pour PowerShell était le Posix Shell qui utilise $? pour le code de sortie

$? est une _exception_ dans les shells de type POSIX ; vous ne pouvez _pas_ faire ce qui suit :

# bash, ksh, zsh, dash (all common /bin/sh implementations)
foo?='bar' # BOOM! E.g. "bash: foo?=bar: command not found"

(Et, évidemment, personne ne demande que $? soient abolis dans PowerShell.)

Et, bien entendu, il convient de mentionner que _toutes les autres_ variables automatiques dans le même espace que $? (c'est-à-dire $^ et $$ ) sont explicitement spéciales- enfermé dans le tokenizer. Et, en fait, il en va de même pour $? , même si cela n'a (actuellement) pas besoin de l'être.

Il me semble clair qu'il était prévu au moment où ce code a été écrit que ? ne serait pas un caractère d'identification valide.

Je ne connais qu'une seule personne qui a utilisé ? à la fin des noms de variables dans leurs scripts, et c'est @StartAutomating. Puisqu'il a en fait utilisé cette syntaxe, j'ai pensé qu'il valait la peine d'attirer son attention sur cette discussion.

Aussi @vexx32 , la raison pour laquelle $? est une casse spéciale dans le tokenizer est que vous ne pouvez pas créer une variable avec un nom qui commence par ? . par exemple, $??? = 'foo' ne sera pas analysé. Les noms de variables doivent commencer par des caractères alphanumériques ou un trait de soulignement et peuvent actuellement contenir des caractères alphanumériques, des traits de soulignement ou des points d'interrogation. Je suis d'accord pour dire que ?. doit être analysé comme l'opérateur d'accès aux membres conditionnel null, mais je voulais clarifier pourquoi ? est une casse spéciale dans le tokenizer.

Merci d'avoir attiré mon attention sur ce chat.

Pour ce que ça vaut, j'ai quelques réflexions :

  1. Bien que ces variables soient rares, personne ne veut jouer à whack-a-mole lorsque la rétro-compat casse ses scripts
  2. Mis à part les gens profondément geeks, je m'attendrais à ce que ${obj}?.Method() ou $obj?.Method() augmente peu. Il y a une décennie de conseils sur le Web sur la façon de gérer les valeurs nulles, et je ne vois pas beaucoup de gens passer de if ($obj) { $obj.Method() } _juste pour prendre le train v7_
  3. De plus, la plupart des gens qui ont des problèmes avec des noms de variables inattendus apprennent la syntaxe ${} (vous l'auriez déjà touché naturellement avec un trait de soulignement). Je m'attendrais à ce que le chevauchement du diagramme de Venn de "personnes qui souhaitent utiliser cette fonctionnalité" à "personnes qui connaissent déjà la syntaxe $ {}" soit proche de 100%
  4. Étant donné que cette syntaxe n'est pas aussi puissante qu'une sous-expression complète et que les sous-expressions complètes fonctionnent à la fois dans le noyau et non, je m'attends à ce que la plupart des gens continuent à l'utiliser à l'avenir.

Donc, en faisant le calcul, il y a plusieurs raisons concrètes _de ne pas_ faire cela, et une seule vague raison de le faire (ce _pourrait_ être plus facile, pour certains utilisateurs). Compte tenu de la faible prévalence de ? dans les noms de variables, vous _pourriez_ aider plus de gens que vous n'en blessez, mais à mon avis, c'est un tirage au sort.

Compte tenu de ce potentiel d'avantages au tirage au sort, je paraphraserai Robert McNamara "Si nous sommes damnés si nous le faisons et damnés si nous ne le faisons pas, je choisirai damné si nous ne le faisons pas".

Je suggère de le faire pour que $obj?.Method() fonctionne comme $<var i="6">obj</var> ?. <var i="9">Method</var>() par défaut, et ne revienne qu'à $<var i="11">obj?</var> . <var i="14">Method</var>() quand $obj n'existe pas dans la portée, mais $obj? est et #requires ‑Version n'est pas v7+.

@ExE-Boss, cela semble être beaucoup d'exceptions à faire pour cette règle particulière.

Je réitère ma questionnement sur la valeur de cette règle particulière.

Au-delà de cela, la question est « que d'autre ne savons-nous pas sur la syntaxe des variables que nous pourrions casser ? »

Si le consensus est de forcer la syntaxe ${...} pour cela, la prise en charge de OptionalFeatures serait appréciée ici, afin que les gens comme moi qui utiliseront cette syntaxe (je l'utiliserai _beaucoup_) puissent se retirer du bruit .

Puisque nous paraphrasons ici :
"La logique dicte clairement que les besoins du plus grand nombre l'emportent sur les besoins de quelques-uns." - Spock

Donc, en faisant le calcul, il y a plusieurs raisons concrètes _de ne pas_ faire cela, et une seule vague raison de le faire (ce _pourrait_ être plus facile, pour certains utilisateurs).

@StartAutomating : Il y a plusieurs raisons, et elles sont concrètes, pas vagues. En outre, l'un des objectifs de ceci est la simplicité du code. Devoir envelopper les noms de variables avec {} fonctionne directement contre cet objectif.

Je suis avec @mklement0 et @KirkMunro à ce sujet. Personnellement, je trouve la syntaxe ${...}? nature et inutilement complexe. Nous avons déjà eu des changements de rupture et dans ce cas, c'est un petit prix à payer en échange de la clarté.

@StartAutomating

  1. De plus, la plupart des gens qui ont des problèmes avec des noms de variables inattendus apprennent la syntaxe ${} ( vous l'auriez déjà touché naturellement avec un trait de soulignement ). Je m'attendrais à ce que le chevauchement du diagramme de Venn de "personnes qui souhaitent utiliser cette fonctionnalité" à "personnes qui connaissent déjà la syntaxe $ {}" soit proche de 100%

Cela ne tient pas. Les traits de soulignement sont des caractères valides dans les noms de variables.

@vexx32

Il me semble clair qu'il était prévu au moment où ce code a été écrit

Nan.

Échanger les caractères ? $foo.?Property semble non conflictuel, car les noms de propriétés commençant par des points d'interrogation doivent déjà être cités :

PS C:\> $foo = [pscustomobject]@{'?'=1; '?name'=2}
PS C:\> $foo.?name
At line:1 char:6
+ $foo.?name
+      ~
Missing property name after reference operator.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingPropertyName
PS C:\> $foo.'?name'
2

@HumanEquivalentUnit , malheureusement, cela inviterait à une confusion éternelle avec la syntaxe ?. établie ${arr}?[0] ) également, et quelque chose comme $arr[0]? prêterait à confusion avec l'opérateur ternaire)

Il n'y a pas de bonne solution.

  1. Un nombre inconnu de personnes utilisent ? à la fin d'un nom de variable. Bien qu'il s'agisse d'une fonctionnalité facultative, on peut dire "Ne l'activez pas si vous exécutez ces scripts", mais la personne qui l'active doit vérifier les scripts actuels et futurs qu'elle obtient de n'importe quelle source.
  2. La syntaxe alternative n'est pas une bonne option car elle importe quelque chose de pas très puissant à partir de C#
  3. Le changement de comportement basé sur #requires ne fonctionne pas en dehors d'un script enregistré et échouera dès que quelqu'un copie du code à partir d'un long script sans définir la balise.
    4. (dir *.ps2)?.count et (dir *.ps1)?.count montrent que cet opérande n'a pas besoin d'être une variable.
    ($Host)?.toString() / ($null)?.toString() supprime le besoin de mettre des accolades autour du nom. C'est toujours des frappes supplémentaires, mais c'est plus logique et moins moche.
  1. Le changement de comportement basé sur #requires ne fonctionne pas en dehors d'un script enregistré et échouera dès que quelqu'un copie du code à partir d'un long script sans définir la balise.

Cela s'applique à _tout_ code qui utilise des fonctionnalités non prises en charge dans les versions antérieures.
S'il s'agissait de la préoccupation primordiale, aucune nouvelle fonctionnalité de langue ou nouveau paramètre d'applet de commande/applet de commande ne serait jamais introduit.

(J'espère que dans le code plus ancien, vous avez au moins Set-StrictMode -Version 1 en vigueur, auquel cas $var?.foo échouerait bruyamment, car aucune variable nommée var? n'existe).

  1. supprime le besoin de mettre des accolades autour du nom.

Remplacer (...) par {...} n'est qu'une amélioration marginale.

Quelle que soit la syntaxe supplémentaire utilisée, le problème ici est le _besoin_ d'une syntaxe supplémentaire - pour quelque chose qui devrait simplement fonctionner _en l'état_ - non seulement pour la commodité de frappe, mais aussi pour répondre aux _attentes raisonnables_.

  1. Le changement de comportement basé sur #requires ne fonctionne pas en dehors d'un script enregistré et échouera dès que quelqu'un copie du code à partir d'un long script sans définir la balise.

Cela s'applique à _tout_ code qui utilise des fonctionnalités non prises en charge dans les versions antérieures.
S'il s'agissait de la préoccupation primordiale, aucune nouvelle fonctionnalité de langue ou nouveau paramètre d'applet de commande/applet de commande ne serait jamais introduit.

Ce n'était pas tout à fait ce que je voulais dire. Plus haut, il a été suggéré que si # nécessite un pwsh 7 spécifié, le traitement pourrait être différent. Allumer un nouveau comportement uniquement si vous mettez #requiresn'est pas bon.

(J'espère que dans le code plus ancien, vous avez au moins Set-StrictMode -Version 1 en vigueur, auquel cas $var?.foo échouerait bruyamment, car aucune variable nommée var? n'existe).

D'après mon expérience, très peu utilise Set-Strictmode. Parce que (a) il y a une hypothèse selon laquelle la valeur par défaut sans elle est "correcte" et (b) la fréquence d'utilisation des choses qui dépendent de son éteint est trop élevée. C'est une utilisation courante pour ces opérateurs. Dans tous les cas, le problème est un code plus ancien où $var? existe et a une propriété foo, mais maintenant le code recherche $var... Il est possible que le nouveau traitement provoque une erreur SI le mode strict est défini car $var n'existe pas....

  1. supprime le besoin de mettre des accolades autour du nom.

Remplacer (...) par {...} n'est qu'une amélioration marginale.

Oui. ($x) est légèrement meilleur que ${x} mais seulement légèrement. ( Get-user "Bob")?.disable() vaut mieux que

$u = get-user "bob" 
($u)?.disable

Quelle que soit la syntaxe supplémentaire utilisée, le problème ici est le _besoin_ d'une syntaxe supplémentaire - pour quelque chose qui devrait simplement fonctionner _en l'état_ - non seulement pour la commodité de frappe, mais aussi pour répondre aux _attentes raisonnables_.

Oui.
$var. foo Avec des espaces blancs. ${foo} ?.bar() pas parce que ? est autorisé dans une fonction ou un nom d'alias (?. est légal pour les deux). Lier des bits de syntaxe C# dans les règles de syntaxe existantes sans casser les choses n'est pas toujours pratique Parfois, "Ceci est disponible en C#..." mérite vraiment la réponse "Oui. Vous savez où se trouve C# si vous le voulez".
:-)

Pour maintenir la compatibilité SemVer , cela doit être fait dans une version majeure (de préférence 7.0.0 ).

Voir également ma suggestion ci-dessus ( https://github.com/PowerShell/PowerShell/issues/11379#issuecomment-566756120 ).

@ExE-Boss Oui, c'est à votre commentaire que je faisais référence quand j'ai dit que selon #requires, ce n'était peut-être pas la bonne idée que ça sonne au début.
Et oui, si l'on veut casser des scripts existants, il faut le faire lorsque la version majeure change, donc cela doit être fait rapidement ou attendre la V8

Il s'agit toujours d'une fonctionnalité expérimentale et sont désactivés par défaut dans RC-1 , ce qui, je suppose, restera le même pour un produit d'expédition. Cela permet de modifier le comportement (ou même d'être une deuxième fonctionnalité expérimentale) - cela devrait également bloquer/avertir lorsque vous essayez de créer une variable se terminant par certains caractères. Si je l'active et que je veux ensuite utiliser des scripts avec des noms de variables erronés qui me font porter la responsabilité - bien sûr, cela signifie que les scripts que je télécharge qui le font ont juste l'air "cassés", ce qui est plus tolérable sous la bannière "expérimentale".

Je ne suis pas un développeur PowerShell sérieux ; Je suis venu ici à la recherche d'une solution à un bogue et je suis tombé sur ce problème. Pour les scripts en ligne de commande, j'utilise principalement bash. Je fais probablement partie du groupe démographique que Microsoft essaie de convaincre de passer à PowerShell Core : développeur multiplateforme ayant besoin d'un langage de script rapide qui soit moins pénible que bash.

J'ai souvent trouvé de nombreuses décisions liées à la syntaxe de PowerShell peu intuitives pour les personnes qui ne sont pas principalement des développeurs PowerShell. La dernière fois que j'ai utilisé PowerShell pour quelque chose de sérieux, j'ai été consterné par l'absence d'un opérateur de fusion nul, ou même d'un opérateur ternaire que je pourrais utiliser à la place, ce qui m'a amené à publier cette réponse PowerShell populaire sur Stack Overflow . C'était en 2013, et c'est facilement l'une des trois principales raisons pour lesquelles j'ai principalement évité PowerShell depuis. L'intérêt d'un langage de script est que je veux quelque chose de rapide et sale avec beaucoup de sucre syntaxique, pas d'instructions if-else verbeuses.

@StartAutomating a dit :

Mis à part les gens profondément geeks, je m'attendrais à ce que ${obj}?.Method() ou $obj?.Method() augmente peu. Il y a une décennie de conseils sur le Web sur la façon de gérer les valeurs nulles, et je ne vois pas beaucoup de gens passer de if ($obj) { $obj.Method() } juste pour prendre le train v7

Je suis juste n=1, mais en tant que développeur non-PowerShell, je ne suis pas du tout d'accord. Le nouveau ? la syntaxe est quelque chose que je découvrirais assez rapidement même en tant que personne qui touche PowerShell peut-être une fois tous les quelques mois, et cela augmenterait certainement les chances que j'utilise PowerShell à l'avenir à la place d'alternatives. Si je vois ensuite qu'une syntaxe {} folle est requise pour la compatibilité descendante, je vais lever les yeux au ciel et revenir à ce que j'utilisais déjà.

Je ne comprends pas l'accent mis sur la compatibilité descendante ici. PowerShell Core a déjà cassé la plupart de mes scripts existants car ils utilisaient des parties de .NET qui ne sont pas dans .NET Core. (Je ne m'en plains pas - .NET Core est génial, mais si vous voulez rompre la compatibilité descendante, c'est votre chance.)

Tout d'abord, je pense que mes premiers commentaires ont créé un malentendu.

Ma supposition était que ${} ne serait pas _si étrange pour les développeurs PowerShell_ , car ils devraient déjà connaître cette forme de syntaxe s'ils avaient déjà intégré une variable avec un ? ou et soulignement dans une chaîne.

Merci pour les nombreux rappels que cette syntaxe peut être gênante pour les développeurs non-PowerShell.

La deuxième partie de mes commentaires s'est peut-être perdue dans le mélange : étant donné que d'autres alternatives à la fusion nulle existent depuis plus de temps dans PowerShell et sont largement utilisées, je ne sais pas dans quelle mesure la fonctionnalité aurait _avec les utilisateurs existants de PowerShell_. Vous voulez entrer et dire "c'est la seule chose dont j'ai besoin pour commencer à utiliser PowerShell", et je ne peux pas contester votre opinion (bien que je puisse dire qu'il vous manque une forêt de fonctionnalités intéressantes à la recherche d'un arbre de langage familiarité).

La troisième partie de mes commentaires semble avoir été exagérée. Parlant en tant que l'une des personnes qui a occasionnellement utilisé des variables nommées comme $IsThisRight ? = Test-Something , ma première réaction en entendant les nouvelles potentielles sur cette restriction de variable a été « eh bien, je suppose que je vais devoir renommer certaines variables, de toute façon je n'en recevais pas grand-chose ».

Donc, pour essayer de reformuler et de terminer le fil:

  1. À mon humble avis, ${} ne sera probablement pas une syntaxe si étrange pour les développeurs PowerShell _existants_
  2. Vous pouvez penser que cette fonctionnalité est cool ; pour moi, c'est un médicament de passerelle de familiarité linguistique, et je recommanderais fortement à tous ceux qui lisent ce fil d'apprendre à basculer l'attribution des ifs/foreaches/whiles, etc.
  3. En tant que l'un des auteurs concernés, je ne reçois pas quelque chose d'aussi critique de la part d'un ? à la fin de mes variables que je serais opposé à changer mon code.

Ou, pour être concis :

Faites ce changement si vous le souhaitez. J'ai peu de cheval dans cette course. Si vous décidez de le faire, veuillez diffuser le changement clairement afin que toute autre personne ayant nommé des variables avec un ? peut mettre à jour en conséquence.

La deuxième partie de mes commentaires s'est peut-être perdue dans le mélange : étant donné que d'autres alternatives à la fusion nulle existent depuis plus de temps dans PowerShell et sont largement utilisées, je ne sais pas quelle augmentation la fonctionnalité aurait avec les utilisateurs PowerShell existants.

Je suis tout à fait d'accord avec cela, et je ne veux pas rejeter votre opinion. Il est toujours difficile de faire des changements aussi décisifs, surtout lorsque l'alternative peut être intuitive pour les personnes qui sont déjà de gros utilisateurs de la langue.

Vous voulez entrer et dire "c'est la seule chose dont j'ai besoin pour commencer à utiliser PowerShell", et je ne peux pas contester votre opinion (bien que je puisse dire qu'il vous manque une forêt de fonctionnalités intéressantes à la recherche d'un arbre de langage familiarité).

Eh bien, j'ai eu le sentiment que la plupart des développeurs non PowerShell ne participent pas vraiment à ces conversations - c'est une pure coïncidence si je suis tombé sur cela. Mon utilisation de PowerShell sera probablement très différente de celle des personnes qui écrivent des bibliothèques et des outils open source. J'ai pensé que je donnerais simplement le point de vue de quelqu'un qui utilise moins PowerShell comme framework sophistiqué et plus pour accomplir des tâches étranges le plus rapidement possible. Il ne s'agit pas de rejeter toute autre opinion - c'est juste une autre opinion d'un point de vue qui n'est probablement pas souvent vu ici.

Une meilleure gestion des valeurs nulles n'est pas la seule chose dont j'ai besoin pour commencer à utiliser davantage PowerShell : c'est la deuxième chose. Le premier était le support multiplateforme, et je suis très impressionné par le chemin parcouru. Personnellement, le sucre de syntaxe est un gros problème pour moi lorsque je choisis un langage pour effectuer une tâche donnée : je veux que la syntaxe facilite ce que je fais. Si j'écris quelque chose qui doit être maintenu par beaucoup de gens, je vais probablement vouloir que ce soit plus détaillé ; mais si j'écris un script rapide pour des tâches administratives ou de développement, je veux juste un moyen rapide de tester des choses comme null.

La troisième partie de mes commentaires semble avoir été exagérée. Parlant en tant que l'une des personnes qui a occasionnellement utilisé des variables nommées comme $IsThisRight ? = Test-Something , ma première réaction en entendant les nouvelles potentielles sur cette restriction de variable a été « eh bien, je suppose que je vais devoir renommer certaines variables, de toute façon je n'en recevais pas grand-chose ».

Favoriser la rétrocompatibilité est toujours un argument juste. Cependant, dans ce cas particulier, il semble que de nombreux scripts PowerShell soient sur le point de se briser en raison de la transition vers Core de toute façon. Lorsque la rétrocompatibilité est régulièrement interrompue, c'est frustrant, mais je serais favorable à ce que tout changement important se produise en même temps, ce qui signifie que c'est probablement le bon moment.

Dans un scénario dans lequel vous essayez de cibler un tout nouveau groupe démographique, c'est-à-dire des développeurs non centrés sur Windows, il peut être nécessaire d'apporter des modifications décisives pour rivaliser avec ce qui existe déjà.

Si vous décidez de le faire, veuillez diffuser le changement clairement afin que toute autre personne ayant nommé des variables avec un ? peut mettre à jour en conséquence.

Pour être clair, je n'ai aucun problème à avoir besoin d'opter pour la fonctionnalité - cela ne me dissuaderait pas d'utiliser PowerShell. Je suis déjà habitué à avoir besoin d'un tas de commandes set en haut de mes scripts bash. Je ne le considérerais pas comme idéal, mais cela aurait peu d'impact sur ma décision d'utiliser PowerShell tant qu'il est bien documenté.

Personnellement, le sucre de syntaxe est un gros problème pour moi lorsque je choisis un langage pour effectuer une tâche donnée

Alors vous avez choisi la bonne langue ! PowerShell est positivement sacchrine avec du sucre syntaxique.

Pour éduquer ceux qui ne le savent pas, vous pouvez « null coalese » de plusieurs manières dans PowerShell :
~$ListWhereNotNull = $null, 1, 2, $null, 3 -ne $null # Ceci vérifiera que chaque élément n'est pas nul et renverra une liste de 1,2,3$FirstNonNull = @($null, 1, $null,2 -ne $null)[0] # Cela renverra le premier non-null$lastNonNull = @($null, 1, 2, $null -ne $null)[-1] # Ceci renverra le dernier non-null, en utilisant un index négatif$TheObjectPipelineWay = $null, 1, $null, 2 | Sélectionner-Objet -Premier 1$TheAssigningForeachWay = foreach (élément $ dans $null, 1, 2, $null, 3, 4) {if ($élément -ne $null) { $élément;



C'est suffisant pour l'instant, mais cela devrait prouver que la syntaxe du langage a beaucoup de flexibilité. Toutes ces démos fonctionneront jusqu'à PowerShell 1.0

Cependant, dans ce cas particulier, il semble que de nombreux scripts PowerShell soient sur le point de se briser en raison de la transition vers Core de toute façon.

En cela, vous vous trompez. Le noyau a en fait très peu de changements de syntaxe, et plus de modules que vous ne le pensez fonctionnent très bien sur le noyau (+- quelques problèmes avec les chemins/nouvelles lignes Linux vs Windows). En termes plus pratiques, votre module est moins susceptible de fonctionner sur Core si vous avez une sorte de dépendance API spécifique à la plate-forme Windows (par exemple, je ne vais pas retenir mon souffle pour que mes wrappers WPF fonctionnent sur Linux).

Je suis toujours d'accord avec le changement de syntaxe : j'ai juste senti que deux des affirmations de la dernière réponse devaient être adressées et appelées.

Re: Sucre syntaxique, mon esprit sarcastique cite le film "Snatch": "Je suis déjà assez mignon"
Re : briser les potentiels de changement dans Core : nous en avons peu maintenant, et gardons-le ainsi autant que nous le pouvons.

@StartAutomating : Êtes-vous en train de dire que je ne peux pas tirer ? car il y a encore de la place pour plus de sucre je pense

Pour éduquer ceux qui ne le savent pas, vous pouvez « null coalese » de plusieurs manières dans PowerShell :

J'ai compris cela (c'est ma propre réponse que j'ai écrite), mais cela ressemblait à un kludge. C'est une bonne idée avec beaucoup de potentiel, mais comme l'a souligné un intervenant sur cette réponse de Stack Overflow, l'évaluation ne court-circuite pas. L'opérateur ?. signifie que ce n'est généralement plus un problème lors de l'enchaînement des appels/propriétés. En 2013, cependant, il n'était pas disponible - et, même alors, il se passe énormément de choses dans ces exemples, et vous pouvez voir dans les commentaires comment les gens ont trouvé cela déroutant. J'ai dû décomposer exactement ce que ces exemples font symbole par symbole.

En cela, vous vous trompez. Le noyau a en fait très peu de changements de syntaxe, et plus de modules que vous ne le pensez fonctionnent très bien sur le noyau (+- quelques problèmes avec les chemins/nouvelles lignes Linux vs Windows). En termes plus pratiques, votre module est moins susceptible de fonctionner sur Core si vous avez une sorte de dépendance API spécifique à la plate-forme Windows (par exemple, je ne vais pas retenir mon souffle pour que mes wrappers WPF fonctionnent sur Linux).

Je parle simplement d'expérience à cet égard, plutôt que de passer en revue et de rassembler des statistiques appropriées. Par exemple, avant Core, je pourrais générer un mot de passe avec [System.Web.Security.Membership]::GeneratePassword(32, 6) , mais System.Web n'est pas disponible dans Core. (Je sais que je pourrais probablement charger l'ancien System.Web.dll, mais je préfère ne pas le faire si ce n'est pas nécessaire.) Les modifications de syntaxe sont en fait plus faciles à résoudre pour moi que les API manquantes. Générer un tas de secrets Docker pour un kit de développement semble être un excellent endroit pour utiliser un script rapide, mais il est étonnamment plus détaillé dans PowerShell Core que bash. Bien sûr, les solutions de bash ont souvent l'air assez moches.

Re: Sucre syntaxique, mon esprit sarcastique cite le film "Snatch": "Je suis déjà assez mignon"

Ça dépend. Parfois, j'ai l'impression que PowerShell est extraordinairement agréable. Traiter avec null est l'un de ces domaines clés où je ne me sens généralement pas de cette façon - bien que je dirais la même chose pour beaucoup de langues. Je trouve également que l'instruction if-else en ligne traditionnelle de PowerShell est lourde par rapport à un opérateur ternaire ou au chaînage && et || bash. Comme il s'agit de l'un des problèmes clés qui m'ont poussé à m'éloigner de PowerShell il y a des années, j'ai pensé que cela valait la peine d'être mentionné.

D'un autre côté, je gère quotidiennement une grande variété de langues, et peu importe ce que j'écris, je me dis toujours "ce serait tellement plus facile dans la langue X !" - et puis quand J'utilise la langue X, je me dis "ce serait tellement plus facile en langue Y !" Mais bon, si j'ai l'occasion de le dire à voix haute et peut-être d'influencer la direction de la langue, je la prendrai.

Je ne suis pas vraiment intéressé à changer d'avis ici, juste à ajouter une autre perspective.

@StartAutomating : Êtes-vous en train de dire que je ne peux pas tirer ? car il y a encore de la place pour plus de sucre je pense

Je m'aime toujours un nouveau sucre de syntaxe ! Je sélectionne des langages de programmation comme un gamin qui fait un tour de passe-passe à Halloween.

@Zenexer : J'aime vraiment Powershell , vraiment. J'ai la chance de faire du PS intensivement et quotidiennement au travail. J'aime la flexibilité, en particulier la symbiose avec .NET, oh mec ! C'est pourquoi je me soucie de sa direction et c'est pourquoi la syntaxe ${...}? est si difficile à accepter pour moi.

Bons points, mais permettez-moi de clarifier certaines choses.

Pour le meilleur ou pour le pire, PowerShell n'a pas utilisé à ce jour le contrôle de version sémantique.
Une nouvelle version majeure n'a apporté que de nouvelles fonctionnalités, avec un engagement à toute épreuve en matière de compatibilité descendante.
Des changements de rupture ont commencé à s'infiltrer dans Core, en partie par nécessité en raison du passage à plusieurs plates-formes.
La version majeure v7.0 a été choisie pour signaler une _augmentation_ de la rétrocompatibilité : une tentative de fournir un remplacement viable pour Windows PowerShell.

Alors que de nombreux problèmes historiques ne peuvent pas être résolus sans casser sérieusement le code existant et ne peuvent donc être proposés qu'en tant que fonctionnalités facultatives (opt-in),
Les modifications de rupture du

Comme indiqué dans le PO, le cas en question me semble être un changement de seau 3 ; alors que nous savons que _certains_ scripts se briseront ( @StartAutomating saura comment réparer ses scripts), les données suggèrent que de tels cas sont assez rares.

Pourquoi est-ce rare ?

Parce que l'utilisation de ? dans les noms de variables ne se produit pas pour la plupart des gens, et si c'est le cas, ils ne devraient pas s'attendre à ce que cela fonctionne _sans {...} _ : si tout ce qui suit ne fonctionne qu'avec {...} , pourquoi s'attendre à ce qu'il soit différent pour ? ? : . , ; ( : ne peut pas du tout être utilisé, car il est toujours interprété comme un séparateur d'entraînement)

Autoriser des noms tels que $var? ou $va?r sans exiger également {...} était une permissivité qui demandait des ennuis, et les ennuis sont arrivés : ils entravent l'évolution de la langue, comme dans ce cas.

Il y a 3 nouvelles fonctionnalités liées (au moins liées sous forme syntaxique) inspirées de C# :

  • Conditions ternaires - seront une fonctionnalité de bonne foi dans 7.0

    • (Get-Date).Second % 2 ? 'odd' : 'even'

  • Opérateur de fusion nulle - sera une fonctionnalité de bonne foi dans 7.0

    • $var ?? 'default' et $var ??= 'default'

  • L'opérateur conditionnel nul - le problème à résoudre - sera une fonctionnalité _expérimentale_ dans la 7.0

    • $possiblyNull?.ToString()

Tous ont ? dans leur syntaxe, et tous sont affectés par le fardeau de l'analyse syntaxique héritée de $var? , bien que ?. plus manifestement :

  • Bien que vous puissiez affirmer que quelque chose comme $var?1:0 n'intéresse que les golfeurs de code, cela fonctionnerait très bien si ? avait une fonction syntaxique - actuellement, vous devez utiliser un _espace_ avant le ?

  • En revanche, il me semble raisonnable que quelqu'un tente $var??='bar' (peut-être moins $baz = $foo??$bar ), qui nécessitent actuellement également un espace.

Autrement dit, si nous nous en tenons à l'analyse actuelle de $var? , nous encombrons _trois_ nouvelles fonctionnalités (bien qu'à des degrés divers), dont 2 sont déjà généralement disponibles (non expérimentales).

Le problème avec l'exigence de {...} n'est _pas_ juste l'inconvénient de taper : il s'agit tout autant de _ne pas en attendre le besoin_ en premier lieu, et plus tard _oublier le besoin_ (avec un dysfonctionnement potentiellement subtil) - parce que c'est tellement contre-intuitif.

@ExE-Boss, je suis d'accord avec @jhoneill que la mise en œuvre d'un comportement conditionnel à la version serait problématique. Je ne pense pas qu'il soit nécessaire d'encombrer le moteur d'un boîtier spécial à compatibilité descendante dans ce cas.

@mklement0 : Ce n'est pas naturel/contre-intuitif/votre nom. Les crochets sont durs, les crochets bouclés encore plus. Ils ne sont pas nécessaires dans ce cas.

@mklement0 puisque l'accord semble éclater ... Je pense que c'est un bon résumé.

Je ne suis pas encore complètement convaincu par l'ajout de constructions C# à PowerShell. Nous avons déjà des problèmes dans de nombreux endroits où il n'y a tout simplement pas assez de symboles sur le clavier. Est-ce que ">" "supérieur à" ou "redirection vers" ? Est-ce "=" affectation ou test-égalité (différentes langues utilisent := pour assigner ou == pour égalité). Les personnes qui sautent d'une langue à l'autre oublieront d'utiliser -eq ou -gt et nous sommes coincés avec ça... Est + addition arithmétique, ou concaténation chaîne/tableau. * est à la fois une multiplication et un joker. % est Modulo et un alias pour forEach-object.

Pauvres ? Est l'alias de Where-Object. Et est le nom d'une variable automatique. Mais essayez de faire Get-Alias ? ou Get-Variable ? ... et ensuite il fait le travail d'un joker.

Faites Get-PSdrive et vous voyez "variable", etc. À moins bien sûr que vous ayez écrit "$drive="C" et que vous le suiviez de "$drive:temp" Toute personne nouvelle sur PowerShell (et les anciens, quand ils n'y pensent pas) sera déconcerté de savoir qu'ils ' Je viens d'inventer un scope nommé "drive".

Alors contre ça... on pourrait dire "Créez une nouvelle syntaxe avec d'autres utilisations pour ":" et "?" êtes-vous fou?'
L'IIRC, sur twitter @BrucePay a décrit l'opérateur ternaire comme "Pas très PowerShelly" et j'ai tendance à être d'accord. Mais les voix "Make it more like C#" ont remporté la victoire...

La plupart des gens écriraient $PSEdition.length -gt 2
mais $PSEdition. length-gt2 fonctionne également (vous pouvez même avoir un saut de ligne entre les deux moitiés.) "." est également surchargé servant de "répertoire actuel", "exécuter dans cette étendue" et "membre". Cependant, dans PS V1-V5, je ne vois aucun opérateur nécessitant un espace de début ; "." est étrange en cas de rupture si un _is_ présent. Mais, pour analyser, l'opérateur ternaire _pourrait_ avoir besoin d'un espace de début
$host.debuggerEnabled?0:1 est OK parce que "?" supposé _pas_ faire partie d'une propriété
$IsCoreCLR?0:1 n'est pas parce que "?" est supposé faire partie du nom de la variable.

Il en est de même pour les opérateurs de coalescence nuls
$null?? "default" besoin d'un espace $true.length?? "default" n'en a pas.

Mettez le cas d'utilisation d'origine en haut du problème de côté pendant un moment. Les cas ci-dessus montrent que quelque chose ne fonctionne pas tout à fait. Il serait corrigé si les noms de variables contenant "?" devaient être contreventés comme les noms contenant "." ou "+" ou ":" , et @StartAutomating qui est l'utilisateur principal de "?" in names pense que c'est un _break qui pourrait être manipulé_. Avant même d'arriver aux membres nuls, cela ressemble à "trouver un moyen de le faire déjà"

Je pense qu'il y a une courte fenêtre de temps pour mettre en place une fonctionnalité expérimentale nécessitant ? être contreventé dans les noms, et si cette fonctionnalité est activée - quelle devrait être la valeur par défaut - tout est nouveau ? les opérateurs doivent analyser en conséquence. Ce n'est que si cette fonctionnalité est désactivée que l'analyseur aura besoin d'espaces ou d'accolades avec ces opérateurs. ?.tostring() étant la première erreur dans un script, les scripts doivent donc échouer, ne pas s'exécuter dangereusement). et idéalement, cela ne devrait pas arriver avec une version ponctuelle (vous avez raison de dire que PowerShell n'utilise pas vraiment sem-ver, mais c'est toujours un bon principe)

Le problème d'exiger {...} n'est pas seulement l'inconvénient de taper : il s'agit tout autant de ne pas en attendre le besoin en premier lieu, et d'oublier plus tard le besoin (avec un dysfonctionnement potentiellement subtil) - car il donc contre-intuitif.

C'est un bon point et c'est en grande partie ce qui m'ennuierait à propos de ${...?} en pratique. Même si je sais utiliser {} , il y a de fortes chances que je finisse par oublier, et cela pourrait entraîner des bugs subtils qui ne sont pas évidents au début, car il sera probablement toujours valide sur le plan syntaxique. $var??='bar' est un bon exemple, même si je fais généralement très attention à l'espacement.

Merci, @jhoneill , c'est une belle illustration du nombre de symboles qui font beaucoup de double (triple, ...) devoir dans PowerShell.
Pour la plupart, une fois que vous êtes au courant de toutes les utilisations, ce n'est pas un problème, pour les raisons suivantes :

  • différents contextes (par exemple, * en tant qu'opérateur contre * tant que caractère générique.)

    • Les différents contextes de ? ont en fait quelque chose en commun, à un certain niveau d'abstraction : vous pouvez concevoir les ? dans Get-ChildItem | ? Target , $var?.Target , $? , $var ?? 'none' comme tous impliquant une sorte de _question_ et donc _test_ ou _comportement conditionnel_.

  • comportement polymorphe sensible (par exemple, + effectuant une concaténation avec une chaîne).

Un exemple problématique est & (opérateur d'appel contre opérateur d'arrière-plan), qui est utilisé dans le même contexte avec une sémantique différente, dépendant uniquement de sa _position_.

Il serait corrigé si les noms de variables contenant "?" devaient être contreventés comme les noms contenant "." ou "+" ou ":"

En effet, et cela mérite d'être répété : la possibilité d'utiliser ? dans les noms de variables ne disparaîtra pas - mais vous devrez utiliser {...} à l'avenir : ${var?} = @{ foo=1 }; ${var?}?.foo

Comme vous le démontrez, du point de vue de quelqu'un qui _ne_ s'attend pas à ce que ? soit un caractère valide. . pour le dot-sourcing étant l'exception justifiable ; ? comme Where-Object alias nécessitant un espace après peut être surprenant (par exemple, gci|?target ne fonctionne pas), mais les noms de commandes _do_ doivent être séparés de leurs arguments par des espaces).

Pouvoir mettre un espace entre . et un nom de membre ( $obj. foo ) a principalement du sens dans les déclarations multilignes, bien que la forme sans doute plus lisible - familière dans d'autres langages - soit (également) autoriser les espaces _avant_ le . :

# This does NOT work - the . must be *immediately after* the expression / member
(Get-Date)
  .ToUniversalTime()  
  .TimeOfDay

Pouvoir le faire refléterait la possibilité récemment ajoutée de placer | sur la ligne _next_ :

 # Already works in PS Core
Get-Date
  | % ToUniversalTime
  | % TimeOfDay

Cependant, cela introduirait des ambiguïtés insolubles avec . comme opérateur de recherche de points et les noms de commandes commençant par . - même si c'est peu probable. (par exemple, . foo sur une nouvelle ligne pourrait être un accès à une propriété ou une commande qui dot-source une fonction ou un script nommé foo (qui devrait être dans $env:PATH ) ; .foo pourrait être le nom d'une _commande_).

La RFC de continuation multi-lignes de @KirkMunro , tout en permettant aux _commandes_ de s'étendre sur plusieurs lignes, nous donnerait la prochaine meilleure solution - voir https://github.com/PowerShell/PowerShell-RFC/pull/179#issuecomment -498734875.

Quant à la fonctionnalité expérimentale étant activée par défaut: Heureusement, _preview_ versions - mais pas libérer les candidats - maintenant tourner _tous_ fonctionnalités expérimentales par défaut; Cependant, notez que cela est constamment remplacé si vous avez déjà exécuté Enable-ExperimentalFeature soit _sans_ -Scope soit avec -Scope CurrentUser avec les fonctionnalités que vous y avez activées.

@mklement0 Bien que je sois d'accord avec tout cela, je crains que nous ne soyons en train de faire dérailler un peu cette discussion particulière avec les éléments supplémentaires que vous avez là; si vous souhaitez résoudre le problème de continuité de ligne autour de l'opérateur dot-property, vous souhaiterez peut-être ouvrir un nouveau problème pour cela s'il n'y en a pas déjà un. ??

Je suis d'accord que continuer à autoriser ? tant que caractère de nom de variable normal est au mieux extrêmement déroutant pour les utilisateurs, car l'utilisation du caractère rend soudainement les choses sensibles aux espaces, et historiquement du moins, je ne pense pas que les noms de variables _jamais_ été sensible aux espaces dans le passé.

L'introduction de cette ambiguïté est, je pense, plus un problème que de faire un changement radical et d'interdire l'utilisation de ? dans un nom de variable. Avec le changement radical, nous pouvons facilement créer une règle PSSA pour alerter les auteurs que la syntaxe n'est plus autorisée. Cependant, l'inverse n'est pas si facilement vrai, et contrairement au changement décisif, il n'y aura pas nécessairement d'erreur ; il peut très facilement se retrouver avec des utilisateurs référençant accidentellement la mauvaise variable en silence, sans savoir que c'est ce qu'ils font.

@PowerShell/powershell-committee en a discuté, nous avions analysé le corpus de scripts PowerShell et il y avait pas mal d'utilisation de noms de variables se terminant par le point d'interrogation. En tant que tel, nous ne pouvons pas casser ces personnes et les accolades autour des noms de variables PowerShell sont une fonctionnalité de langage existante pour distinguer le nom de la variable des autres caractères (comme dans une chaîne).

nous avions analysé le corpus de scripts PowerShell et il y avait pas mal d'utilisation de noms de variables se terminant par le point d'interrogation

Merci, @SteveL-MSFT - pouvez-vous partager les résultats de cette analyse ?

Oui, je serais curieux de voir une partie de cela, car je suis conscient que certains membres de la communauté ont fait leur propre analyse et n'ont rien obtenu de ce genre de résultat.

J'aimerais aussi voir les résultats et la méthode utilisée. J'ai fait ma propre analyse du PowerShell Corpus hier soir à l'aide de l'AST, ce qui a pris près de 6 heures sur ma machine. Il y avait un petit nombre de fichiers qui n'ont pas pu être analysés en raison de la mise en quarantaine du fichier par Windows Defender.

J'ai trouvé 11 noms de variables uniques dans 8 fichiers se terminant par un point d'interrogation (à l'exclusion de $? qui s'est affiché 8846 fois). Il y avait un total de 1 895 983 variables uniques dans 408 423 fichiers. Cela signifie que 0,0006 % de toutes les variables PowerShell uniques du corpus ont un nom de variable se terminant par un point d'interrogation.

Voici les 8 fichiers et 11 variables uniques :

File                 : C:\Temp\PowerShellCorpus\Github\alanrenouf_PowerActions\Kill-VM.ps1
QuestionMarkVars     : vParam?
QuestionMarkVarCount : 1

File                 : C:\Temp\PowerShellCorpus\Github\anthonywlee_PowerShell\Send_Notification.ps1
QuestionMarkVars     : To?
QuestionMarkVarCount : 1

File                 : C:\Temp\PowerShellCorpus\Github\aspear_My-PowerCLI-scripts\my-labotomize-vms.ps1
QuestionMarkVars     : vParam?
QuestionMarkVarCount : 1

File                 : C:\Temp\PowerShellCorpus\Github\jlundstrom_Scripts\Powershell\7Zip SFX Creator\Build.ps1
QuestionMarkVars     : Title?
QuestionMarkVarCount : 1

File                 : C:\Temp\PowerShellCorpus\Github\pslaughter_Working\Setup-Host.ps1
QuestionMarkVars     : HostIp?
QuestionMarkVarCount : 1

File                 : C:\Temp\PowerShellCorpus\Github\stevenayers_PowerShell-Scripts\Random Functions\Add-OutlookConferenceRegionNumber.ps1
QuestionMarkVars     : {key1?, key2?, key3?, key4?}
QuestionMarkVarCount : 4

File                 : C:\Temp\PowerShellCorpus\Github\unixboy_powershell-stufff\stopvm.ps1
QuestionMarkVars     : vParam?
QuestionMarkVarCount : 1

File                 : C:\Temp\PowerShellCorpus\PowerShellGallery\PsHg\0.6.2\PsHg.psm1
QuestionMarkVars     : PsHg?
QuestionMarkVarCount : 1

Voici le script utilisé pour générer le rapport :

Get-ChildItem -Path C:\Temp\PowerShellCorpus -Include *.ps1, *.psm1 -File -Recurse | ForEach-Object -Parallel {
    try {
        $content = $PSItem | Get-Content

        $ast = [System.Management.Automation.Language.Parser]::ParseInput($content, [ref]$null, [ref]$null)
        $variables = $ast.FindAll({$args[0] -is [System.Management.Automation.Language.VariableExpressionAst ]}, $true)

        # First query because I forgot to exclude $? variables
        # $nonQuestionMark = $variables | Where-Object VariablePath -notmatch '\?$' | Select-Object -Unique
        # $QuestionMark = $variables | Where-Object VariablePath -match '\?$' | Select-Object -Unique

        $nonQuestionMark = $variables |
        Where-Object VariablePath -notmatch '\?$' |
        ForEach-Object { $_.VariablePath.UserPath.ToString() } |
        Select-Object -Unique

        $QuestionMark = $variables |
        Where-Object { $_.VariablePath -match '\?$' -and $_.VariablePath.UserPath -ne '?' } |
        ForEach-Object { $_.VariablePath.UserPath.ToString() } |
        Select-Object -Unique

        $output = [pscustomobject]@{
            File = $PSItem
            QuestionMarkVars = $QuestionMark
            QuestionMarkVarCount = $QuestionMark.Count
            NonQuestionMarkVars = $nonQuestionMark
            NonQuestionMarkVarCount = $nonQuestionMark.Count
        }

        $output
    }
    catch {
        throw
    }
}

Faites-moi savoir s'il y a un problème avec la méthode utilisée pour générer ce rapport. Voici un exemple de script utilisé pour tester l'audit.

$abc = 'test'
$isAwesome? = $true
$?

$test = {
    $?
    $isabc? = { $adce? = 'test' }
    ${def?} = 123
    ${is a bad var name?} = $isabc?
}

Résulte en:

File                    : C:\temp\variable.ps1
QuestionMarkVars        : {isAwesome?, isabc?, adce?, def?, is a bad var name?}
QuestionMarkVarCount    : 5
NonQuestionMarkVars     : {abc, true, test}
NonQuestionMarkVarCount : 3

Comme on dit en cours de maths, "s'il te plaît, montre ton travail"

Excellent détective, @ThomasNieto - merci.

Je pense que vous pouvez potentiellement éliminer encore plus de cas, étant donné que la forme ${...} continuera à fonctionner avec le changement proposé - par exemple, c'est seulement $isAwesome? nous devons nous inquiéter, pas ${isAwesome?}

Avec ton fichier exemple :

$variables.Extent.Text.Where({ $_ -match '(?<!\$)\?$' }) | Select-Object -Unique

on n'obtient que :

$isAwesome?
$isabc?
$adce?

C'est-à-dire que ${def?} et ${is a bad var name?} n'ont pas besoin d'être pris en compte.

PS : Il est probablement aussi préférable d'utiliser $PSItem | Get-Content -Raw pour lire l'intégralité du script sous la forme d'une seule chaîne.

@mklement0 C'est correct, j'ai ajouté ces cas juste avant de publier pour m'assurer que le script n'excluait pas tous les variables avec la notation d'accolades.

Après avoir mis à jour le script avec vos recommandations, le fichier de test produit la sortie suivante comme prévu.

File                    : C:\temp\variable.ps1
QuestionMarkVars        : {isAwesome?, isabc?, adce?}
QuestionMarkVarCount    : 3
NonQuestionMarkVars     : {abc, true, test}
NonQuestionMarkVarCount : 3

J'ai exécuté le script mis à jour sur ces 8 fichiers et aucun d'entre eux n'utilise la notation d'accolades, donc le résultat est que 11 variables uniques seraient impactées par le changement proposé.

Script mis à jour :

Get-ChildItem -Path C:\Temp\PowerShellCorpus -Include *.ps1, *.psm1 -File -Recurse | ForEach-Object -Parallel {
    try {
        $content = $PSItem | Get-Content -Raw

        $ast = [System.Management.Automation.Language.Parser]::ParseInput($content, [ref]$null, [ref]$null)
        $variables = $ast.FindAll({$args[0] -is [System.Management.Automation.Language.VariableExpressionAst ]}, $true)

        $nonQuestionMark = $variables |
        Where-Object VariablePath -notmatch '\?$' |
        ForEach-Object { $_.VariablePath.UserPath.ToString() } |
        Select-Object -Unique

        $QuestionMark = $variables |
        Where-Object { $_.VariablePath -match '\?$' -and $_.VariablePath.UserPath -ne '?' -and $_.Extent.Text -match '(?<!\$)\?$' } |
        ForEach-Object { $_.VariablePath.UserPath.ToString() } |
        Select-Object -Unique

        $output = [pscustomobject]@{
            File = $PSItem
            QuestionMarkVars = $QuestionMark
            QuestionMarkVarCount = $QuestionMark.Count
            NonQuestionMarkVars = $nonQuestionMark
            NonQuestionMarkVarCount = $nonQuestionMark.Count
        }

        $output
    }
    catch {
        throw
    }
}

Merci, @ThomasNieto - J'espérais que nous pourrions réduire le pourcentage à 0,0005%... (je plaisante).

Donc le comité a dû utiliser un autre - privé ? - corpus.

Ainsi, en plus de trancher le problème posé, la question se pose : le corpus accessible au public a-t-il besoin d'être mis à jour ? Est-il officiellement maintenu (actuellement en date du 26 juillet 2017) ?

@SteveL-MSFT, pouvez-vous clarifier s'il vous plaît ?

@mklement0 J'ai arrondi, donc si vous voulez vous sentir un peu mieux, c'est en fait 0,00058% 😄

Dans https://github.com/PowerShell/PowerShell-RFC/pull/223#discussion_r318340339 @adityapatwardhan a fait une analyse en utilisant le même corpus public que j'ai utilisé et a trouvé 62% avec des variables se terminant par un point d'interrogation. Je n'ai pas vu de réponse sur la façon dont il a obtenu ce pourcentage. Le comité PS a-t-il utilisé cette analyse pour déterminer cette demande?

En regardant le commentaire lié, je pense que @adityapatwardhan dit que _parmi toutes les variables qui ont ? dans leur nom_ 62% ont un ? comme _dernier_ caractère du nom.

En revanche, votre analyse de la prévalence réelle des variables (sans accolades) se terminant par ? (en pourcentage de l'utilisation globale des variables) semble beaucoup plus pertinente.

À ce stade, il semble que le comité dise simplement « nous ne voulons pas » et si tel est le cas, pourquoi même avoir cette fonctionnalité si elle va être maladroite et inutilisée en conséquence ?

@ThomasNieto De même, j'ai fait une analyse quelque part autour de ces problèmes et j'ai

@mburszley Merci d'avoir fait votre analyse. Je voulais utiliser une autre méthode (ast vs regex) pour confirmer les résultats que vous avez obtenus l'année dernière.

Je vous entends, @mburszley , mais re:

le comité dit simplement "nous ne voulons pas"

S'il s'agissait vraiment d'une décision _fiat_ - une décision non fondée sur une analyse de l'utilisation du monde réel - cela ne présagerait rien de bon pour la communauté dans son ensemble, d'autant plus que la raison _énoncée_ était un fondement dans une telle analyse.

Ainsi, nous devrions donner au comité une chance de montrer l'analyse d'utilisation dans le monde réel sur laquelle la décision était basée - ou de reconnaître que l'analyse a échoué et de reconsidérer la décision.

Qu'en est-il de ma suggestion dans https://github.com/PowerShell/PowerShell/issues/11379#issuecomment-566756120 ?

Je suggère de le faire pour que $obj?.Method() fonctionne comme $<var i="9">obj</var> ?. <var i="12">Method</var>() par défaut, et ne revienne qu'à $<var i="14">obj?</var> . <var i="17">Method</var>() quand $<var i="19">obj</var> n'existe pas dans la portée, mais $<var i="21">obj?</var> est et #requires ‑Version n'est pas v7+.

Je m'attendrais à ce que cela résolve la plupart des problèmes de compatibilité descendante.

@ThomasNieto

@mklement0 est correct, je voulais dire que parmi les variables utilisant ? , 62% l'utilisent à la fin.

D'après les résultats présentés en commentaire , toutes les variables qui utilisent ? utilisent à la fin. D'où la proposition d'effectuer un changement sans rupture.

Si l'exigence de {..} est supprimée, le script sera toujours analysé mais la sémantique sera différente, ce qui, à mon avis, est très dangereux.

Bien sûr... mais l'analyse montre littéralement que presque personne ne les utilise.

Identique à tout autre changement de rupture, il peut être annoncé, introduit en tant que fonctionnalité expérimentale pendant un certain temps, puis documenté et introduit dans la version stable.

Je ne vois aucune raison de recommander une syntaxe ésotérique lorsque ? comme caractère d'identification n'est pas réellement utilisé dans un nombre de cas à distance significatif.

Si l'exigence de {..} est supprimée, le script sera toujours analysé mais la sémantique sera différente, ce qui, à mon avis, est très dangereux.

Ne craignez-vous pas également que les gens utilisent ?. comme ils le font en C/C++/C# et obtiennent le mauvais résultat sans indiquer qu'ils ont fait quelque chose de mal ? Par exemple:

PS> $res = "My length is 15"
PS> $res?.Length
0

Bien sûr, le mode strict trouvera cela, mais je ne sais pas si beaucoup de gens utilisent le mode strict. Donc, pour éviter qu'un très petit pourcentage de scripts ne se brise, il semble que nous préparions beaucoup de gens à l'échec en utilisant ?. . Je ne suis pas fou du compromis. Cela dit, je comprends parfaitement le désir d'éviter de casser les gens même s'il s'agit d'un très petit nombre de personnes.

Peut-être que PowerShell a besoin d'un équivalent de Enable-ExperimentalFeature appelez-le Enable-PSFeature , pour les fonctionnalités qui ne sont plus à l'état expérimental mais qui ne sont pas prêtes à être activées par défaut . Pour les scripts qui s'exécutent avec du code comme celui-ci $?.GetType() vous pouvez commencer à émettre des avertissements indiquant qu'à l'avenir, cela se brisera et que vous devriez utiliser ${?}.GetType() place. Des scripts individuels pourraient activer la fonctionnalité avec un #requires -version 7.1 -feature PSNullConditionalOperators . Alors peut-être que chaque fois que PS 8 frappe, la fonctionnalité pourrait être activée par défaut.

L'exemple de @rkeithhill va droit au but.
Oubliez un instant ce que vous savez sur le fonctionnement de PowerShell aujourd'hui. Quand tu vois

PS> $res?.Length

Cela ressemble à _nom, opérateur, nom_ - ce dont il s'agit bien sûr.
Ce qui aurait plus de sens : _"?" fait partie de l'opérateur_ , ou _"?" fait partie du prénom-élément_ ?
Si ces opérateurs sont nécessaires (et je pense qu'ils ne sont "pas PowerShelly"), c'est un choix entre quelque chose qui sera utilisé de manière incorrecte et une petite quantité de casse.

Je commencerais à mettre des règles dans psScriptAnalyzer _now_ pour dire que c'est un mauvais style d'utiliser certains caractères [légaux] dans les noms de variables.

Je n'aime pas Enable-feature . Quelqu'un le met dans un script pour faire fonctionner quelque chose qu'il veut utiliser, et un ancien script se brise s'il est exécuté après le nouveau script (mais fonctionne le reste du temps). J'ai vu _le script tiers X échoue après l'exécution du script Y_ parce que Y active le mode strict et X compte sur sa désactivation ; les auteurs des deux scripts sont dans mes mauvais livres.

Je commencerais maintenant à mettre des règles dans psScriptAnalyzer pour dire que c'est un mauvais style d'utiliser certains caractères [légaux] dans les noms de variables.

Voici le problème : si vous modifiez la façon dont PowerShell jette les variables, PSScriptAnalyzer les verra également différemment. Si vous avez une variable comme $res? , regardez quelque chose comme ceci :

{
$res?.Length
}.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Expression.VariablePath.UserPath

vous donne

res?

MAIS, si vous modifiez la façon dont PowerShell est analysé, disons, 7.2, vous obtiendrez


Désormais, PSScriptAnalyzer ne peut pas voir le ? , car il ne fait plus partie du nom de la variable (par définition, puisque c'est le changement que nous essayons de tester). En effet, PSScriptAnalyzer est un module PowerShell et réutilise le même analyseur que celui fourni dans PowerShell. (Et ce serait totalement impossible à maintenir et une recette pour le désastre s'il essayait de le réimplémenter).

Il existe des moyens de contourner cela, comme la compilation conditionnelle de PSScriptAnalyzer (et l'envoi d'un tout nouvel assembly) pour tester la nouvelle logique 7.2 afin de fournir le même diagnostic. Mais ensuite, vous avez augmenté la complexité partout (ou au contraire diminué votre surface de test) pour répondre à un scénario quelque peu cosmétique.

Pire encore, tous les autres outils qui reposent également sur l'AST n'auront pas la capacité de supporter ce type de complexité, même si PSScriptAnalyzer le fait. La plupart des personnes qui créent des outils de ciblage AST ne vont pas compiler avec des versions mineures individuelles de PowerShell pour une exactitude parfaite. Ils ne seront probablement même pas au courant d'un si petit changement de rupture, d'autant plus qu'il ne s'agit d'une erreur dans aucune version ; c'est la forme la plus insidieuse de changement radical, où un comportement en devient tranquillement un autre.

C'est essentiellement ce qui rend les changements au niveau de l'analyseur/tokeniseur comme celui-ci plus dangereux. Même PSScriptAnalyzer doit se plier en quatre pour les entretenir correctement, ce qui signifie qu'ils doivent être mis en balance avec des changements aussi onéreux.

@rjmholt , bien que je pense que nous pouvons tous comprendre à quel point un changement comme celui-ci est délicat _en principe_, dans ce cas particulier, cela n'a pas d'importance _en pratique_, et je ne pense pas qu'une règle PSSA soit même nécessaire :

  • L'analyse de @ThomasNieto a montré que - si nous pensons que le corpus est représentatif de tout le code PowerShell existant - que _pratiquement personne n'utilise de variables dont les noms se terminent par ? _.

  • Si je devais deviner, la plupart des gens ne penseraient même pas à utiliser de tels noms de variables, car ils ne s'attendraient pas à ce qu'ils fonctionnent (moi inclus), et ne remarqueraient probablement même pas l'exception selon laquelle le $? automatique $? constitue (dont le nom est également une exception dans les shells compatibles POSIX tels que bash ).

    • En fait, un examen plus attentif de l'analyse de 8 répertoriés :

      • 5 ne contiennent que des _faux positifs_, à savoir des variables utilisées à l'intérieur de _chaînes_ telles que "Are you sure you want to kill $vParam?" - en fait, ces utilisations sont _cassées_, et révèlent que les auteurs du script _pas_ s'attendaient ? ce que

      • 2 de ces fichiers ne sont plus accessibles au public.

      • Seuls _1_ d'entre eux sont une utilisation de bonne foi des variables de terminaison $key1? ), qui, en passant, ne sont donc _pas_ combinées avec l'opérateur d'accès aux membres , . /cc @stevenayers.

Sur la base de ce qui précède, cela me semble être un manuel Bucket 3: Improbable Gray Area change, qui est donc _acceptable_ - et je pense que les _avantages_ de ce changement ont été argumentés de manière convaincante.

_Documenter_ le changement de comportement (avec une justification) devrait suffire.

Bien sûr:

  1. ceci est fondé sur (a) que l'analyse soit correcte et (b) que le corpus accessible au public soit représentatif.

  2. c'est tout à fait en contradiction avec l'affirmation du comité selon laquelle "il y avait beaucoup d'utilisation de noms de variables se terminant par le point d'interrogation" (ce qui, bien sûr, ne serait un problème que si de tels noms de variables ne sont pas inclus dans {...} ).

En partant du principe que 1. est vrai (nous n'avons rien entendu à l'appui de 2.), nous avons deux options :

  • Déchirez le pansement et interdisez simplement ? dans les noms de variables à l'avenir, à moins qu'il ne soit inclus dans {...} (à l'exception évidente de $? ) - cela brisera le minuscule proportion de scripts qui reposent actuellement sur cela.

    • C'est-à-dire quelque chose comme $key1? qui n'est suivi ni de . ni d'un autre ? ( $key1??'else' ) ni d'une expression ternaire ( $key1?1:0 ) provoquerait une _erreur d'analyseur_.

      • Comme le montrent les exemples de fusion nulle et d'opérateur ternaire, eux aussi bénéficieraient de ce changement - actuellement, vous avez soit besoin d'un _space_ - $key1 ?1:0 / $key1 ??'else' - ou {...} - ${key1}?1:0 / ${key1}??'else'

    • À l'intérieur des _chaînes extensibles_, ? ne seraient plus considérés comme faisant partie d'un nom de variable (non inclus dans {...} ), donc nous _réparerions_ les scripts existants qui ont utilisé par erreur des chaînes telles que "Are you sure you want to kill $vParam?" . ??
  • Si nous pensons vraiment que nous devons éviter de casser la proportion infime de scripts existants, nous _pourrions_ considérer la logique proposée par @ExE-Boss , mais je ne pense pas que nous voulions introduire cette complexité conceptuelle - et encore moins la complexité d'implémentation (que j'ai je ne peux pas vraiment parler).

@SteveL-MSFT

Merci d'avoir discuté de ce problème lors de l'appel communautaire de septembre (https://aka.ms/PSCommunityCall ; au moment d'écrire ces lignes, l'enregistrement de l'appel de septembre n'y a pas été publié, mais est accessible à l'adresse https://aka.ms/JoinPSCall, jusqu'au prochain appel), à partir de 46h00, sur la base de la suggestion de https://github.com/PowerShell/PowerShell-RFC/issues/260 :

(J'espérais fournir un lien direct vers la partie pertinente de l'enregistrement, mais cela devra attendre qu'il soit publié sur YouTube et lié à https://aka.ms/PSCommunityCall.)

Sur la base de vos remarques dans l'enregistrement :

  • Étant donné que vous avez indiqué votre volonté de réexaminer ce problème, veuillez rouvrir ce problème et le marquer à nouveau comme Review - Committee .

  • Quant à vos remarques selon lesquelles l'inclusion des noms de variables dans des accolades est une caractéristique préexistante et que les gens s'opposent à l'obligation de les utiliser dans ce cas pour des raisons _esthétiques :

    • Je pense que personne ici _n'est_ au courant que {...} _peut_ et parfois _doit_ être utilisé pour lever l'ambiguïté des noms de variables.
    • Il ne s'agit pas non plus d'_esthétique_, il s'agit principalement de _ne pas obtenir le comportement attendu_ d'une manière qui _échoue discrètement_, car _ne s'attend pas à devoir utiliser {...} dans ce cas_ ; une préoccupation secondaire est la gêne de frappe.
GitHub
Documents RFC (Request for Comments) pour les commentaires de la communauté sur les modifications de conception et les améliorations apportées à l'écosystème PowerShell - PowerShell/PowerShell-RFC
Équipes Microsoft

Je crains que ce problème - maintenant apparemment indéfiniment dans un état fermé - passe entre les mailles du filet, j'ai donc ouvert le #14025 pour me rappeler de le revoir, et j'invite tous ceux qui sont intéressés à y montrer leur soutien.

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