Powershell: Suggestion: implémenter une fusion nulle, un accès conditionnel nul (trempage nul), une affectation conditionnelle nulle

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

L' accès à fusion nulle et

_Update_: @BrucePay suggère également un _assignment_ conditionnel nul , avec ?= - voir le commentaire ci-dessous .

Par exemple, au lieu d'écrire:

if ($null -ne $varThatMayBeNull) { $varThatMayBeNull } else { $fallbackValue }
#
if ($null -ne $varThatMayBeNull) { $varThatMayBeNull.Name } else { $null }

on pourrait être capable d'écrire:

$varThatMayBeNull ?? $fallbackValue  # null-coalescing
# 
$varThatMayBeNull?.Name   # null-conditional access, for Set-StrictMode -Version 2+
$varThatMayBeNull?[42]  # ditto, with indexing

Accès conditionnel nul: Avec Set-StrictMode étant OFF (par défaut), vous pouvez simplement utiliser $varThatMayBeNull.Name - aucune syntaxe spéciale n'est nécessaire; cependant, si Set-StrictMode -Version 2 ou plus est en vigueur, $varThatMayBeNull.Name _breaker_ et c'est là que l'opérateur conditionnel nul ( ?. ) est utile, pour signaler l'intention explicite d'ignorer le $null de manière concise.


Question ouverte :

$varThatMayBeNull?[42] gère le cas où la variable est $null , mais si ce n'est pas le cas, un élément de tableau avec l'index spécifié _doit exister_.

Il serait donc également utile de rendre _indexing_ null-conditionnel - quelque chose que C # ne prend pas en charge, d'ailleurs (vous devez utiliser .ElementAtOrDefault() ).

Les deux choix de base sont:

  • Trouvez une syntaxe supplémentaire qui signale explicitement l'intention d'ignorer un _index_ inexistant:

    • La question est de savoir quelle syntaxe choisir pour cela, étant donné que ?[...] et [...]? ne sont pas une option en raison de l'ambiguïté.
    • Peut-être [...?] , mais cela semble gênant.
  • Fiez-vous au comportement existant en ce qui concerne l'accès à des index inexistants, comme l'implique le paramètre Set-StrictMode - voir le tableau ci-dessous .


Connexes: implémenter des conditions ternaires

Issue-Enhancement Resolution-Fixed WG-Language

Commentaire le plus utile

@rjmholt J'ai fait une analyse ici . Une ventilation rapide: sur près de 400 000 scripts avec plus de 22 000 000 noms de variables (non uniques), il n'y avait que ~ 70 variables uniques qui se terminaient par ? .

Tous les 71 commentaires

@ mklement0 Il semble que le deuxième exemple fonctionne par conception sans "?".
Peut-être changer en name() ?

@iSazonov : Bon point, mais cela ne fonctionne que sans ? moins que Set-StrictMode -Version 2 ou supérieur ne soit _pas_ en vigueur - j'ai mis à jour le message initial pour le préciser.

Je pense que le sucre syntaxique est quelque chose que PowerShell pourrait utiliser que d'autres langues apprécient. +1 sur la proposition.

Considérez les exemples suivants d'autres langues:

a="${b:-$c}"
a = b || c;
a = b or c
a := b ? c
a = b ? b : c;

même

a = b if b else c

est mieux que

if (b) { a = b } else { a = c }

et souvent, vous avez besoin de clarifier avec le plus verbeux

a = (si (b -ne $ null) {b} autre {c})

Fait que l'on se sent tout sale et dénigré.

Je me suis retrouvé à faire cela aujourd'hui pour contourner le problème.

`` PowerShell
$ word = ($ null, "deux", "trois"). Où ({$ _ -ne $ null}, "First")
`` ``

J'utilise un modèle similaire:

$word = ($null, "two", "three" -ne $null)[0]

@kfsone Il y a une petite erreur dans votre exemple $a=(if ($b -ne $null) { $b } else { $c }) . Cela devrait être $a=$(if ($b -ne $null) { $b } else { $c }) cependant la seule version de PowerShell où $( ) était requis était la version 1. À partir de la v2, vous pouvez simplement faire:

$a = if ($b) { $b } else { $c }

@bgshacklett Vous ne voulez pas dire $word=($null,'two')[$null -ne 'three'] ?

C'est un peu dommage que cela soit passé de 6.1 à 6.2 à "Future".

@ TheIncorrigible1 Non, si vous copiez et collez ce que j'ai ajouté ci-dessus, vous devriez voir que la valeur de $word est définie sur "deux". Il y a plus de détails dans cette réponse Stack Overflow où j'ai vu le modèle pour la première fois:
https://stackoverflow.com/a/17647824/180813

Alors que les hack-around de perlesque font appel à moi qui ai écrit il y a 20 ans un shebang qui a enregistré et / ou interrogé un enregistrement d'utilisateur ou d'organisation RIPE-DB, ce que j'espère de PowerShell est quelque chose qui encourage mes collègues à utiliser le langage plutôt que de leur instiller la peur.

Mon test décisif est le suivant: Voudrais-je lire ceci via ma tablette à 3 heures du matin le matin du Nouvel An alors que le PDG au téléphone me pleurait combien de millions de dollars nous perdons une seconde.

(À part: ce n'était qu'une exagération lâche d'une expérience réelle jusqu'à ce que je travaille chez Facebook et que je revienne d'une fuite rapide et urgente pour me dire que, dans les 2 minutes de mon absence, plus de personnes que la population néerlandaise avaient obtenu un vide. Ce n'était pas mon code et l'erreur était un changement minime dans la sémantique de return x vs return (x) dans la norme c ++ pour des cas de modèle très spécifiques, et "voudriez-vous lire ce code en 2 minutes date limite, une vessie pleine et le sort de chaque sabot portant des photos de chat de Hollandais sur votre épaule ???

Ouaip. Il existe des astuces intéressantes possibles dans PS qui sont excellentes à la rigueur ou si vous avez besoin d'une sténographie ponctuelle.

Pour le code maintenable, idéalement, nous devrions avoir des opérateurs de fusion null explicites comme C #. Le principal problème pour moi est - que utilisons-nous pour cela? ? est déjà aliasé sur Where-Object (bien que j'aimerais que cela soit effacé, c'est très courant). Remarquez que % est aliasé sur ForEach-Object mais cela n'empêche pas les opérations de module, donc en théorie au moins avoir ? serait également un opérateur de fusion nul bien; il ne serait interprété comme tel que dans les expressions, où Where-Object n'est pas vraiment valide de toute façon.

@ vexx32 :

Au moins _syntactiquement_ ?? devrait être bien, car nous parlons du mode _expression_, alors que ? , en tant que commande [alias], n'est reconnu qu'en mode _argument_.
Je ne sais pas si la réutilisation du symbole est source de confusion, mais ce ne serait pas la première fois qu'un symbole a un double devoir dans différents contextes.

Étonnamment, utiliser ?. et ?[] pour le trempage nul serait techniquement un changement radical, car PowerShell autorise actuellement ? comme caractère non initial dans un nom de variable.

PS> $foo? = @{ bar = 1 }; $foo?.bar   # !! $foo? is a legal variable name
1

Cependant, j'espère que cela serait considéré comme un seau 3: changement

Je ne peux pas dire que j'ai déjà vu quelqu'un utiliser? sous un nom variable ... Moi non plus, car il y a de fortes chances que ce soit mal interprété. Mais oui, j'espère que cela devrait être parfaitement utilisable.

Je soupçonne qu'il est un peu tard pour en parler, mais Bash a géré cela (et certains autres cas) avec ses fonctionnalités de substitution de paramètres: https://www.tldp.org/LDP/abs/html/parameter-substitution.html.

Bien que cela puisse être un ours à apprendre en raison du grand nombre de choses qui peuvent être faites avec, il est incroyablement puissant. Je comprends qu'il ne serait pas possible d'utiliser cette notation exacte en raison de la façon dont PowerShell utilise des accolades avec des variables, et que cela ne correspondrait pas nécessairement à la sensation générale du langage, mais cela semble être un point de données utile.

@bgshacklett :

Oui, la substitution de paramètres est puissante, mais, malheureusement, ce n'est pas seulement un ours pour _apprendre_, mais aussi pour _ se souvenir_.

Ainsi, alors que les caractéristiques de Bash sont souvent intéressantes, leur forme syntactique est souvent obscure, difficile à retenir et ne convient pas à PowerShell.

_Brace expansion_ (par exemple, a{1,2,3} dans bash passant à a1 a2 a3 ) est un exemple d'une fonctionnalité intéressante dont j'aimerais voir l'expressivité dans PowerShell, mais avec PowerShell-approprié syntaxe - voir # 4286

Je suis complètement d'accord. Je l'ai évoqué plus comme un exemple de la façon dont ce problème a été résolu ailleurs que comme une solution exacte.

Il y a un autre opérateur à envisager:

$x ?= 12

qui définirait $x s'il n'est pas défini (n'existe pas). Cela fait partie du "modèle d'initialisation" qui n'est pas courant dans les langages conventionnels mais pour les langages (à portée dynamique) comme les shells, les outils de création, etc. il est assez courant d'avoir un script qui définit une valeur par défaut si l'utilisateur ne l'a pas spécifié . (Bien qu'en fait les initialiseurs de paramètres soient assez répandus.)

Étendre cela aux propriétés:

$obj.SomeProperty ?= 13

ajouterait et initialiserait une propriété de note SomeProperty sur l'objet s'il n'existait pas.

Et - pour le plaisir - une autre variation sur l'initialisation d'une variable en utilisant -or :

$x -or ($x = 3.14) > $null

$x ?= 12 semble être une excellente idée.

Il m'est apparu que nous devrions probablement appliquer tous ces opérateurs non seulement si le LHS n'existait pas, mais aussi s'il _existait mais contenait_ $null (avec [System.Management.Automation.Internal.AutomationNull]::Value traité comme $null dans ce contexte).

ajouter et initialiser une propriété de note SomeProperty

Dans cette veine, $obj.SomeProperty ?= 13 n'a de sens pour moi _seulement_ que si .SomeProperty existe et contient $null , étant donné que vous ne pouvez pas créer implicitement des propriétés même avec des affectations régulières (en revanche, pour la création d'une entrée implicite a du sens).

Tous les opérateurs discutés devront exempter le LHS de la vérification d'existence en mode strict.

Je m'interroge sur l'intention / le raisonnement derrière pourquoi strictmode vous empêche d'accéder à une propriété qui n'existe pas. Est-ce que l'intention d'attraper des fautes de frappe comme $x.pretnd ? L'intention est-elle de vérifier des hypothèses telles que assert(x != null) ? Est-ce que l'intention de bloquer la propagation accidentelle de $null plus loin dans votre code?

le null-soaking (?.) est utile, pour signaler l'intention explicite d'ignorer le $ null d'une manière concise.

N'est-ce pas ce que . signale déjà en mode non strict? Si vous aviez voulu être strict, vous auriez pu vérifier la présence de .Name premier, en ne vérifiant pas d'abord, vous avez déjà signalé une intention explicite que la vérification n'était pas importante pour vous.

Si StrictMode a un but où l'accès à une propriété inexistante et le retour de $null est interdit, alors le même raisonnement ne s'appliquera pas à ?. , et cela devrait lever la même exception pour la même raison . Sinon, pourquoi pas?

Avec null-coalescing, vous pouvez écrire:

$result = Invoke-RestMethod -Uri 'https://example.org/api/test'
$test = $result?.Name

Sera-t-il rapidement recommandé ou idiomatique de toujours utiliser ?. pour chaque référence de propriété, car cela "se comporte comme . et ne lèvera pas d'exceptions pour les personnes utilisant le strictmode"?

Est-ce que le vrai désir d'avoir un mode strict configurable avec des paramètres variables, de sorte que, par exemple, vous puissiez avoir une déclaration en haut de votre script # StrictMode SkipMemberExistenceCheck , ou un attribut de hachures d'échappement pour indiquer un bloc de unstrict code généralement? [Je soupçonne que le désir est une syntaxe de style C # laconique, mais vous savez ce que je veux dire]

Merci pour les pensées, @HumanEquivalentUnit.

Est-ce que l'intention d'attraper des fautes de frappe comme $x.pretnd ?

Je ne peux pas parler de l'intention de conception, mais c'est ce qui a du sens pour moi - analogue à ce que fait Set-StrictMode -Version 1 pour _variables_ (uniquement).

Avec les variables, il s'agit de leur _existence_, pas de savoir si la valeur se trouve être $null , et la vérification de l'existence d'une propriété suit le même modèle.

Je pense que c'est le plus proche qu'un langage de script dynamique puisse trouver pour trouver des erreurs qu'un langage compilé de type statique rapporterait au moment de la compilation.


N'est-ce pas ça? signaux déjà en mode non strict? Si vous aviez voulu être strict, vous auriez pu vérifier la présence de .Name en premier

Oui, mais en mode non strict, vous renoncez aux vérifications d'existence susmentionnées, et les tests manuels sont évidemment assez fastidieux - et invariablement plus lents qu'une fonctionnalité intégrée.

en ne vérifiant pas d'abord, vous avez déjà signalé une intention explicite selon laquelle la vérification n'était pas importante pour vous.

Le fait est qu'avec Set-StrictMode -Version 2 ou plus, vous obtenez:

  • l'avantage de la vérification de l'existence des membres _par défaut_
  • la possibilité de se désinscrire, _à la demande, de manière concise_ avec .?

vous pourriez avoir une déclaration en haut de votre script # StrictMode SkipMemberExistenceCheck , ou un attribut de hachures d'échappement pour indiquer un bloc de unstrict code général

En relation: La portée dynamique actuelle de Set-StrictMode est problématique; voir @lzybkr le projet de RFC « pour la mise en œuvre d' un mode strict _lexical_: https://github.com/PowerShell/PowerShell-RFC/blob/master/1-Draft/RFC0003-Lexical-Strict-Mode.md

l'avantage de la vérification de l'existence des membres par défaut

PS contient du code qui vérifie les membres et renvoie $ null lorsqu'ils n'existent pas. C'est un avantage par défaut, que vous pouvez également éviter en écrivant votre propre test d'existence de membre avec $x.psobject.properties... si vous le souhaitez. StrictMode enlève cet avantage et évite d'avoir à écrire des tests d'existence. Ensuite, au lieu de donner une bonne façon d'écrire exactement un test d'existence de membre, ?. vous donnerait une solution de contournement concise pour obtenir ce que . toujours fait. Et s'il est important que le membre existe, vous devez toujours le coder séparément.

Mais cela me fait me demander ce qu'il en est des appels de méthode:

$x.pretend     -> $null
$x.pretend()   -> Exception MethodNotFound
$x?.pretend  -> $null
$x?.pretend()   -> ____ what goes here? $null?

set-strictmode -version 2
$x.pretend -> Exception PropertyNotFoundStrict
$x.pretend()  -> Exception MethodNotFound
$x?.pretend  -> $null
$x?.pretend()   -> ____  ?

ie ?. se comporterait de la même façon que . pour les recherches de propriétés en mode non strict, mais se comporterait différemment de . pour les appels de méthode en mode non strict, ce qui le rendrait nuancé et non un remplacement instantané. Cela signifie-t-il qu'en utilisant ?. vous n'auriez aucun moyen de dire si une méthode a été invoquée ou si rien du tout ne s'est passé? Les propriétés peuvent être sauvegardées par des méthodes getter, mais je pense que c'est la convention dans DotNet pour les getters de ne pas muter l'état interne, mais normal pour les appels de méthode à muter l'état. Avec ?. vous n'auriez aucune idée si vous avez muté l'état d'un objet?

Je me demande si vous pouvez obtenir les avantages souhaités, et mieux, en rendant ?? capable de gérer les exceptions PropertyNotFoundException et MethodNotFound directement à partir de l'expression de gauche (mais pas les autres exceptions levées dans les méthodes), ainsi que la gestion de $ nulls, et n'ont pas du tout ?. . par exemple

$varThatMayBeNull ?? $fallbackValue # null-coalescing
#
$varThatMayBeNull.Name ?? $fallbackvalue    # catching PropertyNotFoundStrict exception
$varThatMayBeNull.Name ??  # default fallback is $null
$varThatMayBeNull.Method() ??  # catching MethodNotFound Exception

# and potentially addressing the index case too
$varThatMayBeNull.first.second[3].Method() ??  # catching MethodNotFound Exception, or index not found Exception

Et puis, au lieu de ?. appeler un membre ou accéder à une propriété, cela pourrait être une manière concise de demander si un membre existe, en retournant un [booléen].

Avec le même ajout de syntaxe de ?? et ?. vous pourriez gérer plus de situations, avec moins de chevauchement déroutant.

StrictMode enlève cet avantage et laisse l'empêchement d'avoir à écrire des tests d'existence

L'empêchement d'une personne est le bénéfice d'une autre personne:
Tout dépend de ce que vous voulez qu'il se passe _par défaut_:

  • Si vous êtes convaincu qu'il n'y a pas de _typos_ dans votre code - bien sûr, profitez du comportement _default_ (mode strict désactivé) - et vous n'aurez pas besoin de .? (pour l'accès _property_ - voir commentaire suivant sur _method calls_ et _indexing_).

    • Sur une note _personnelle_: j'ai tendance à utiliser Set-StrictMode -Version 1 pour éviter les fautes de frappe dans les noms _variables_, mais je trouve -Version 2 ou supérieur trop ennuyeux, principalement à cause de # 2798 (qui est un bogue indépendant de cette offre).
  • Si vous voulez vous assurer que vous (a) vous n'avez pas mal orthographié les noms de propriété et / ou (b) que votre code n'opère pas accidentellement sur des types de données autres que ceux sur lesquels vous êtes censé opérer, définissez le mode strict sur la version 2 ou supérieure. .

    • En effet, cela _currently_ rend difficile de _opt out_ de ces contrôles _à la demande_,
    • c'est précisément pourquoi l'introduction d'un accès conditionnel nul est proposée ici: pour faciliter la désactivation à la demande.

Tester explicitement la présence d'un membre est en réalité un cas d'utilisation distinct qui peut être une nécessité quel que soit le mode strict en vigueur.

Quant aux _method calls_, que l'OP ne couvre pas:

_Appels de méthode_ (par exemple, $varThatMayBeNull.Method() ) et _indexing_ (par exemple, $varThatMayBeNull[$index] ) sont deux cas où même le mode strict étant désactivé ou à la version 1 pourrait en bénéficier, étant donné que les deux cas actuellement _invariablement_ provoquent une erreur si la valeur en cours d'accès est $null .

La syntaxe serait la même que pour les propriétés des méthodes - $varThatMayBeNull?.Method() - et analogue pour l'indexation - $varThatMayBeNull?[$index] - comme en C #.

_Update_: Il y a un deuxième aspect à l'indexation, à savoir si la variable est non nulle, mais que l'élément à l'index donné n'existe pas (par exemple, $arr = 0,1; $arr[2] ). Avec la version 2 en mode strict ou inférieure, cela équivaut à $null , mais dans la version 3 ou supérieure, cela provoque une erreur, et ce serait bien de pouvoir également désactiver cette erreur. Cependant, la syntaxe de ce cas présente un défi - voir l'OP mis à jour, qui propose actuellement le [...?] peut-être maladroit.

Et, oui, je fais ce défaut d'accès à $null ainsi, même pour les méthodes - encore une fois, vous êtes _explicitly_ signalant qu'il est bien de ne rien faire si l'objet en cours d' accès $null ou si aucun élément de ce type n'existe.

Notez que C # n'a pas d'indexation conditionnelle null dans le second sens.

Il a une indexation conditionnelle nulle, mais pas tout à fait comme vous le proposez. C # permet (je suis presque sûr, au moins ...) array?[0] qui contourne le problème habituel "index dans un tableau / collection nul" et retourne simplement null.

Mais oui, je suis d'accord que c'est une bonne idée. Cela nous évite de devoir gérer les exceptions et maintient le code assez clair et concis.

@ vexx32 , c'est _un_ aspect de l'indexation conditionnelle nulle: si array dans array?[0] est null , l'opération d'indexation est ignorée - C # l'a aussi, comme vous le dites.

Je parlais (mise à jour: _also_) de l'autre aspect de l'indexation conditionnelle nulle: le cas où array dans array?[0] est _pas_ null mais c'est _l'élément à l'index 0 _ qui n'existe pas.

C'est ce dernier qui ne peut être ignoré en C #, à ma connaissance, mais je pense qu'il serait également utile.

Pouvez-vous penser à une terminologie pour donner à ces deux aspects des noms distincts?

Le code d'un autre problème JavaScript passerait de $_.Description[0].Text à $_?.Description[0?]?.Text ce qui, je pense, n'est pas joli; et mon autre suggestion sur la façon dont ?? pourrait se comporter le porterait à $_.Description[0].Text ?? ce qui est subjectivement plus agréable, et permettrait - si possible de mettre en œuvre - de gérer les échecs à n'importe quel point de recherche de la chaîne en une seule fois , et vous permet toujours de choisir ce que vous voulez qu'il se passe par défaut, et d'avoir une alternative différente à volonté au lieu d'être limité à seulement $null .

En passant, cette syntaxe ?. aurait-elle un analogue pour les propriétés et méthodes statiques, c'est- $t = [int]; $t::MaxValu; $t::Pars("1") dire ?: ou ?:: ?

Quel serait le comportement souhaité pour l'indexation de tableau avec plus d'un index spécifié? $array[0,4?,1,2] où chacun peut être autorisé à échouer, ou $array[0,4,1,2?] avec seulement le lot entier autorisé à réussir ou à échouer?

Je dois d'abord prendre du recul, car je me rends compte que j'ai confondu des aspects qui méritent d'être séparés, du moins conceptuellement:

  • Accès au membre ou à l'index conditionnel _Null-value_-conditionnel, comme en C #:

    • Si une valeur en cours d'accès est $null , ignorez les tentatives d'accès à ses membres ou indexez-la et évaluez à $null .
  • Accès au membre ou à l'index conditionnel _Member-existence_, spécifique à PowerShell:

    • Si une valeur en cours d'accès est _non- $null _, ignorez les tentatives d'accès aux _membres_ non existants (propriétés, appels de méthode, indexation) qui n'existent pas.

Remarque: Par souci de brièveté, j'utilise _member_ de manière assez vague ici pour englober également les _éléments_ d'objets qui se trouvent être des collections, auxquelles on accède avec _indexing_ plutôt que par point.

Si vous êtes convaincu qu'il n'y a pas de fautes de frappe dans votre code - bien sûr, profitez du comportement par défaut (mode strict désactivé) - et vous n'en aurez pas besoin. (pour l'accès à la propriété

@ mklement0 Je pense que vous parlez de la vue " une personne utilisant le mode strict pour améliorer son propre code " et moi de la vue " quelqu'un d'autre peut exécuter mon code en mode strict, quels changements feraient fonctionner mon code pour eux aussi? "et cela me conduit à un raisonnement différent. Avec ?. il serait si pratique de l'utiliser à la place de . et de faire en sorte que le code fonctionne également en mode strict que je pourrais aussi bien l'utiliser partout habituellement; Je ne perds rien et gagne en compatibilité. Je crains que tout le code PowerShell ne soit uglifié de cette façon car il "fonctionne" dans plus de cas.

Mais ce n'est pas un remplacement instantané, car il réduit au silence la recherche d'appels de méthode échoués en mode non strict et les recherches de propriétés échouées en mode strict - il ajoute une nuance délicate à la recherche de membres, une opération incroyablement courante. Cela n'aide pas ceux qui souhaitent bénéficier de contrôles stricts en facilitant ce passe-partout. Cela n'aide pas assez de gens dans suffisamment de situations, pour la complexité que cela ajoute. Et c'est trop pratique de rendre le code plus compatible, je ne pense pas que "l'ignorer si vous ne le voulez pas" soit assez fort pour le tenir à distance.

PowerShell peut faire des choses que C # ne fait pas, comme définir des variables automatiques ou créer un précédent pour que des exceptions soient levées et réduites au silence dans les coulisses. Il doit y avoir une meilleure approche qui ne complexifie pas du tout la recherche des membres, mais simplifie le passe-partout standard des contrôles de sécurité en mode strict afin que les personnes qui souhaitent utiliser les chèques aient une vie plus facile et les personnes qui ont été ennuyées par les chèques ont également une vie plus facile.

@HumanEquivalentUnit Comment fait-il taire ces choses? Vous auriez à écrire une charge de gestion des exceptions et des vérifications nulles auparavant, à la place:

$prop = $item?.Method().PropIwant ?? 'PropActionFailed'

v.

$prop = if ($null -ne $item) {
    $propIwant= $item.Method().PropIwant
    if ($null -eq $propIwant) {
        'PropActionFailed'
    }
    else {
        $propIwant
    }
}

Et ce cas n'est pas rare. Ou vous lancez simplement $ErrorActionPreference = 'Stop' et enveloppez le tout dans try/catch pour simplifier la vérification de null qui est un mauvais modèle (logique basée sur les exceptions).

De plus, c'est l'avenir du langage, ce n'est pas comme si nous retournions à 5.1 et changions les choses. Si vous voulez plus d'adopteurs, vous devez faciliter la lecture du code, ce que je pense faire cette suggestion.

@ mklement0 Je pense que vous parlez de la vue "_une personne utilisant le mode strict pour améliorer son propre code_" et moi de la vue "_ quelqu'un d'autre peut exécuter mon code en mode strict, quels changements feraient fonctionner mon code pour eux aussi? _ "

Parlons-nous de l'équivalent de "set -euo pipefail" (bash strict mode)?

a- Limiter les recherches de variables (bien que je ne vois pas pourquoi vous pensez qu'une simple vérification nulle des recherches de membres serait une mauvaise chose, la recherche de membres réelle est bien plus chère que if (result is null) )
b- Utilisez [Strict] sur les portées / blocs de code pour dire à l'analyseur de les traiter comme tels,
c- La rigueur est basée sur la portée: le code qui n'est pas marqué strict n'est pas strict.

Si j'ai écrit un code strict qui échoue lorsque vous l'utilisez, l'un de nous a fait une erreur. Soit j'ai référencé une variable manquante dans le code que je n'ai jamais testé, soit vous avez mal compris mon API mal conçue qui dépend de l'existence de variables qui ne sont pas transmises à ma fonction et vous n'avez pas réussi à renseigner une variable que je m'attends à être renseignée. .

# Their code
Function Log($Message) { Write-Host $Massege }  # not strict

# My code
[Strict]
Function DebugMsg
{
  Param([String] $Message)
  if ($DEBUG) { Log Host $Message }
}

# Your code
DebugMsg "Hello"  # you didn't define DEBUG, and by saying strict I expressed a contract whereby the variable MUST be defined.

La fonction "Journal" n'a pas été marquée comme stricte, donc elle ne se plaint pas de la faute de frappe

🤔 Maintenant que vous le mentionnez, un attribut [Strict()] serait un moyen génial d'implémenter le mode strict d'une manière restreinte à la portée. Cela doit être mentionné dans cet autre fil de discussion sur les problèmes de mode strict, je vais creuser cela et relier ici ...

@ TheIncorrigible1 " Comment fait-il taire ces choses? " En mode non strict $null.x est silencieux, $null.x() est une exception. Avec ?. comme discuté, $null?.x est silencieux, $null?.x() est silencieux.

Vous auriez donc un . qui fonctionne comme le ?. C #, sauf en mode strict où il lance des exceptions. Ensuite, vous auriez un ?. qui fonctionne en mode strict comme le ?. C # et comme le . PowerShell fonctionne en mode non strict, mais qui fonctionne différemment de . PowerShell ?. est clairement meilleure et plus utile dans plusieurs de ces scénarios).

Vous devrez écrire une charge de gestion des exceptions et des vérifications nulles auparavant, à la place: $prop = $item?.Method().PropIwant ?? 'PropActionFailed'

Votre appel de méthode peut lancer ou renvoyer $ null et PropIWant peut être manquant, vous devrez toujours écrire:

$prop = try {
    $item?.Method()?.PropIwant ?? 'PropActionFailed'  
} catch [someMethodException] {
    'PropActionFailed'
}

vs avec ma proposition ?? (s'il était possible de construire), et pas besoin de ?. , et il couvre les cas possibles d'exceptions de méthode au cas où tout ce qui vous préoccupe est "succès ou non" et aucune gestion détaillée des erreurs.

$prop = $item.Method().PropIWant ?? 'AnythingFailed'

Si vous voulez plus d'adopteurs, vous devez faciliter la lecture du code, ce que je pense faire cette suggestion.

À quelle fréquence tapez-vous . dans PowerShell? À quelle fréquence voulez-vous expliquer aux nouveaux utilisateurs quelle est la différence entre . et ?. et leur dire qu'ils doivent tenir compte de la différence chaque fois qu'ils tapent un . pour toujours ?

«Oh, comment est-ce arrivé? "Eh bien, en C # . lancé une exception pour les membres manquants, ils ont donc inventé ?. ce qui n'a pas été le cas. C'était génial, alors ils l'ont fait dans PowerShell par défaut, le . ne lance pas. Puis ils ont inventé le mode strict qui fait que . se comporte comme C # et lance mais seulement dans ce contexte, mais la façon de vérifier manuellement les membres était vraiment verbeuse et ennuyeuse et personne ne voulait le taper; au lieu de résoudre ce problème de front et de le rendre plus pratique pour bénéficier du mode strict, ils l'ont esquivé et ont évité le ?. C # au lieu de gagner un moyen sournois de sortir de la rigueur que vous avez demandée, ce qui est légèrement pratique pour vous, mais nul pour tout le monde. Et vous n'avez toujours pas de test d'existence de membre, et bénéficier du strictmode est toujours verbeux et gênant, mais au moins vous n'avez pas à en souffrir parce que 'strictmode' a une trappe d'évacuation 'normalmode' maintenant". Ick.

Si j'ai écrit un code strict qui échoue lorsque vous l'utilisez, l'un de nous a fait une erreur.

bien que je ne vois pas pourquoi vous pensez qu'une simple vérification null sur les recherches de membres serait une mauvaise chose, la recherche de membres réelle est bien plus chère que si (le résultat est nul)

Je ne pense pas que ce serait mal, PS non-strictmode le fait déjà, et je pense que ce serait une alternative souhaitable au ?. proposé - très différent, utile dans plus de situations.

Mais notez que dans PS, vous pouvez faire quelque chose que C # ne peut pas:

(1..3)[1kb..100kb]

et aucune exception en mode non strict. Changez les chiffres et voyez combien de temps cela prend; à en juger par la performance et la façon dont je pense que cela doit fonctionner dans les coulisses pour indexer des objets arbitraires, il semble qu'il y ait en fait ~ 100 000 exceptions levées et réduites au silence, pour notre commodité. PS ne fait pas toujours le choix "doit être aussi rapide que possible, pousser les inconvénients sur l'utilisateur", et j'aime ça.

@HumanEquivalentUnit Il existe de nombreuses fonctionnalités dans chaque langue que vous n'utiliserez peut-être jamais dans votre carrière et si vous n'aimez pas le style, c'est très bien, vous n'avez pas besoin d'utiliser ces fonctionnalités. Je ne vois pas pourquoi vous désactivez le mode strict; c'est une bonne pratique dans les scripts, donc vous traitez consciemment les problèmes plutôt que de laisser le langage les avaler (et en substance, avoir des blocs de capture vides implicites partout). Encore une fois, vous pouvez toujours ne pas utiliser les fonctionnalités (par exemple, je n'ai jamais utilisé Out-Default ).

De plus, l'opérateur est ? , et non ?. ; cela fonctionnerait également avec l'accès aux index.

Pour continuer à jeter les bases d'une discussion plus approfondie, permettez-moi de résumer comment les modes stricts existants affectent l'accès conditionnel à valeur nulle et à l'existence de membre conditionnel (les termes présentés ci-dessus ):

Les colonnes ci-dessous représentent les paramètres Set-StrictMode et les valeurs de colonne indiquent:

  • 👍 ... autorisé
  • 🚫 ... interdit (provoque une erreur de fin d'instruction)

En passant: le fait que les erreurs ne se terminent que par _statement-_, pas par _script_, se rapporte à la discussion plus large sur la gestion des erreurs de PowerShell - voir https://github.com/PowerShell/PowerShell-Docs/issues/1583.

  • Accès conditionnel _Null-value_ - $obj _itself_ est $null :

Construire | -Off | -Version 1 | -Version 2 | -Version 3+
---------- | ---- | ---------- | ---------- | ------------
$ obj | 👍 | 🚫 | 🚫 | 🚫
$ obj.Prop | 👍 | 👍 | 🚫 | 🚫
$ obj [42] | 🚫 | 🚫 | 🚫 | 🚫
$ obj.Method () | 🚫 | 🚫 | 🚫 | 🚫

Il est curieux qu'avec -Off et -Version 1 , $obj.Prop est autorisé, alors que $obj[42] ne l'est pas.

  • _Member-existence_-conditional access - $obj n'est pas- $null , mais le membre / élément auquel on accède n'existe pas:

Construire | -Off | -Version 1 | -Version 2 | -Version 3+
---------- | ---- | ---------- | ---------- | ------------
$ obj.Prop | 👍 | 👍 | 🚫 | 🚫
$ obj [42] (indexable) | 👍 | 👍 | 👍 | 🚫
$ obj [42] (non indexable) | 👍 | 👍 | 🚫 | 🚫
$ obj.Method () | 🚫 | 🚫 | 🚫 | 🚫

Il est curieux que les objets intrinsèquement indexables (par exemple, les tableaux) permettent d'accéder à des éléments inexistants même avec -Version 2 , alors que les scalaires - où PowerShell fournit des capacités d'indexation pour une gestion unifiée des collections - ne le font pas.

L'opérateur null-soaking ( conditionnel nul ou Elvis en C # ) est presque obligatoire lors de l'exécution dans StrictMode Latest et en essayant d'accéder à une propriété qui peut exister ou non. Actuellement, vous devez recourir à des astuces stupides comme celle-ci:

function Get-OptionalPropertyValue($object, [string] $propertyName) {
    if (-not ([bool] (Get-Member -InputObject $object -MemberType Properties -Name $propertyName))) {
        return $null
    }

    $object.$propertyName
}

$value = Get-OptionalPropertyValue $foo "bar" # if $foo.bar exists, $value will contain its data; else $value will be $null

quand vous devriez vraiment être capable d'écrire:

$value = $foo?.bar # if $foo.bar exists, $value will contain its data; else $value will be $null

S'il vous plaît les gars, si vous ne pouviez obtenir que des conditions nulles à partir de cette proposition implémentée et uniquement pour les propriétés, cela sauverait tant de gens tant de douleur.

J'ai commencé à y jeter un coup d'œil et j'ai trouvé quelques problèmes.

Considérons ?? et ?=

$x ?= 1 et $x ?? 1 semblent simples. Mais, comme ce sont des opérateurs, nous devons prendre en charge $x?=1 et $x??1 .

Le problème avec cela est que $x? et $x?? valident tous deux les noms de variables dans PowerShell. La seule façon de lever l'ambiguïté serait ${x}?=1 et ${x}??1 .

Et plus encore pour l'accès conditionnel des membres ?. et ?[] , nous devrons avoir ${x}?.name et ${x}?[0] .
Pour ceux-ci, $x ?.name et $x ?[0] ne seront pas pris en charge.

L'autre option est d'introduire un changement de rupture et de ne pas autoriser du tout ? dans le nom de la variable.

Qu'est-ce que tu penses? @ mklement0

/ cc @rjmholt @ daxian-dbw @JamesWTruher

Je n'ai jamais particulièrement _ aimé_ ni compris pourquoi ? est un nom de variable valide. Cela ouvre la porte à des noms comme $Safe? qui sont généralement plus clairs et moins gênants quand ils sont écrits comme $IsSafe toute façon.

Je pense que le changement a probablement été long à venir.

Cela ouvre la porte à des noms comme $ Safe? qui est généralement plus clair et moins gênant lorsqu'il est écrit comme $ IsSafe de toute façon

Fait intéressant, j'ai exprimé le sentiment contraire. C'est une tradition classique de Scheme / Ruby .

if ($questionMark?)
{
    Write-Host "That's silly!"
}

L'opérateur ternaire n'a-t-il pas eu le même problème, où la résolution était d'exiger des espaces autour de l'opérateur ou des accolades autour du nom de la variable pour qu'il fonctionne correctement avec des variables qui se terminent par ? ?

Je m'attendrais à ce qu'avec l'introduction de ces opérateurs, PowerShell donnerait la priorité à la reconnaissance de ? dans le cadre de l'opérateur dans une syntaxe telle que $x?[0] , de sorte que les utilisateurs qui utilisent des noms de variables se terminant par ? pour stocker une collection devrait utiliser cette syntaxe à la place (puisque les espaces seraient invalides dans ce cas): ${x?}?[0] . Idem pour $x?.Name et ${x?}?.Name .

L'autre option est d'introduire un changement de rupture et de ne pas permettre? dans le nom de la variable du tout.

👍 Étant donné qu'il s'agit d'un changement de version majeur (6 à 7), je pense que cela vaut la peine d'un changement de rupture ici. Je souhaite que GitHub ait une meilleure recherche de code pour voir combien d'instances il y a de variables PS qui se terminent par un ? . Je soupçonne que ce ne serait pas si impactant, mais ce serait bien de le vérifier par rapport à GitHub. En 14 ans d'utilisation de PowerShell, je n'ai jamais utilisé un ? dans un nom de variable, mais c'est peut-être juste moi. :-)

Ce navire a navigué il y a longtemps, et je ne serais pas surpris de voir des variables se terminant par ? utilisées dans les scripts aujourd'hui.

À ce stade, si nous donnons la priorité à l'analyse de ? dans le cadre d'un opérateur plutôt que dans le cadre d'un nom de variable lorsqu'il s'agit de ces nouveaux opérateurs, les personnes qui utilisent des noms de variables se terminant par ? auraient besoin pour utiliser {} ou des espaces (où les espaces sont autorisés) pour utiliser ces variables avec ces opérateurs.

Il est étrange d'entendre l'expression «ce navire a navigué» dans ce contexte. Il s'agit d'un changement de _version_ majeure. Il n'est pas déraisonnable que cela change ici, je pense.

@rkeithhill Je l'ai utilisé dans des choses personnelles, mais je pensais que ce ne serait pas clair pour le travail collaboratif car c'est une chose tellement anti-intuitive pour les programmeurs d'avoir des symboles dans les noms de variables (similaire à l'utilisation d'émojis comme variables)

@KirkMunro ayant "l'analyse prioritaire" sonne comme une porte ouverte aux bogues.

@ vexx32 : Ce n'est pas déraisonnable pour un changement de rupture puisqu'il s'agit d'un changement de version majeur; cependant, la barre pour de tels changements de rupture devrait rester très élevée, et je ne pense pas que cela se rapproche de cette barre, car les utilisateurs pourraient utiliser des variables se terminant par ? très bien tant qu'ils utilisent {} englobe pour identifier le nom de la variable.

Notez que vous pouvez également avoir un nom de propriété qui se termine par ? . Actuellement, si vous essayez d'afficher une telle propriété dans PowerShell sans mettre le nom entre guillemets, vous obtiendrez une erreur d'analyseur.

Par exemple:

PS C:\> $o = [pscustomobject]@{
    'DoesItBlend?' = $true
}
PS C:\> $o.DoesItBlend?
At line:1 char:15
+ $o.DoesItBlend?
+               ~
Unexpected token '?' in expression or statement.
+ CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken

PS C:\> $o.'DoesItBlend?'
True

Je suis un peu surpris que cela ne soit pas analysé aujourd'hui (pourquoi ne pas analyser?), Mais peu importe, pour de telles propriétés, vous devez mettre leur nom entre guillemets, auquel cas vous pouvez suivre la citation avec un ternaire, null -coalescing, etc. opérateur sans espaces et cela fonctionnerait très bien. Je trouve cette syntaxe très similaire à ${x?}?.name , et je suis d'accord avec l'idée que vous pouvez utiliser de tels noms de variables / propriétés si vous le souhaitez, mais ces noms peuvent nécessiter une syntaxe ou un espacement supplémentaire pour fonctionner avec ternaire ou null -* les opérateurs.

@KirkMunro Rien

Les utilisateurs de PowerShell 7 sont probablement déjà des passionnés et seront au courant des changements majeurs. Les personnes qui ne le sont pas utilisent encore <= v5.1 et continueront de le faire pendant longtemps; probablement jusqu'à ce que msft le supprime de Windows 10 (jamais).

@KirkMunro Bien sûr, mais le supprimer des caractères de variable standard autorisés n'empêche pas les utilisateurs de simplement faire ${Valid?} comme nom de variable de toute façon. Puisqu'ils devraient le faire avec ces opérateurs de toute façon, je pense qu'il vaudrait mieux que cela soit cohérent, plutôt que de faire de ? un caractère qui n'est parfois considéré comme faisant partie d'un nom de variable.

Cela va déjà être un changement de rupture, et je pense qu'il vaut mieux au moins être cohérent à ce sujet et aller jusqu'au bout plutôt que d'introduire un autre niveau d'ambiguïté. 🙂

@adityapatwardhan Je pense qu'il serait préférable que le langage supprime ? comme caractère variable valide. Cela permettrait facilement d'activer à la fois les opérateurs null-soak / -coalesce et ternaires dans une syntaxe familière qui ajoute beaucoup d'ergonomie au processus de création de script.

@KirkMunro ayant "l'analyse prioritaire" sonne comme une porte ouverte aux bogues.

@ TheIncorrigible1 : Tout code peut ouvrir la porte à des bogues s'il n'est pas implémenté correctement. Je parle simplement d'une simple recherche à un seul caractère pour identifier si PowerShell se heurte à un opérateur ternaire ou nul- * lorsqu'il analyse un nom de variable qui n'est pas inclus dans des limites de variable et rencontre un caractère ? . Ce n'est pas compliqué et n'ouvre pas la porte à plus de bogues que tout autre changement de code.

Les utilisateurs de PowerShell 7 sont probablement déjà des passionnés et seront au courant des changements majeurs. Les personnes qui ne le sont pas utilisent encore <= v5.1 et continueront de le faire pendant longtemps; probablement jusqu'à ce que msft le supprime de Windows 10 (jamais).

@ TheIncorrigible1 : Quelle base / preuve avez-vous de cette déclaration? PowerShell 7 est en préversion, donc aujourd'hui il n'est utilisé que par des passionnés. C'est une évidence. Mais au-delà de l'aperçu, si PowerShell 7 ou version ultérieure offre des fonctionnalités convaincantes dont les entreprises ont besoin, tout en prenant en charge les fonctionnalités dont elles ont besoin, elles utiliseront ces versions. Cela est particulièrement vrai si PowerShell 7 est installé avec le système d'exploitation. Le seul point que les passionnés entrent en jeu est dans les organisations qui n'ont pas besoin de ce que PowerShell 7 apporte à la table.

Cela va déjà être un changement radical, et je pense qu'il vaut mieux au moins être cohérent à ce sujet et aller jusqu'au bout plutôt que d'introduire un autre niveau d'ambiguïté. 🙂

@ vexx32 C'est étirer. Ce serait un changement radical si vous aviez ?? dans un nom de variable, mais la probabilité de cela est beaucoup plus éloignée que d'avoir une variable dont le nom se termine par un seul ? . En dehors de cela, comment l'introduction d'opérateurs null- * tout en prenant en charge ? tant que scripts de rupture de caractères variables standard autorisés aujourd'hui?

D'après mon expérience, les changements de rupture pour les gentils-nantis (ce qui semble être ce que cela semble être) sont de loin le plus souvent rejetés, et les discussions / arguments autour d'eux ne servent qu'à ralentir le processus pour faire avancer les choses le point où les choses calent ou manquent d'entrer dans une version, etc. Le ralentissement est souvent nécessaire, car si vous proposez un changement de rupture, des preuves sont nécessaires pour pouvoir évaluer l'impact et justifier un tel changement. Il est difficile de rassembler ces preuves aujourd'hui. Je dis simplement cela parce que je choisirai de faire des fonctionnalités maintenant plutôt que de discuter d'un changement de rupture agréable n'importe quel jour.

Je n'utilise jamais ? dans les noms de variables, et je ne le ferais pas non plus.Je m'attends à ce que certaines personnes le fassent, car il peut très bien lire dans un script, et mettre en place des barrières inutiles à l'entrée pour PowerShell 7 ralentit simplement l'adoption, en particulier lorsque de nombreuses personnes travaillant avec PowerShell ne sont pas des développeurs plus habitués à travailler sur des changements de rupture.

Quoi qu'il en soit, je n'ai pas l'intention de ralentir ce processus - plutôt le contraire. Mais j'ai partagé mes pensées et mon expérience, donc je ne commenterai pas davantage si nous devrions faire pression pour un changement radical ici.

Considérez cet exemple artificiel:

$ValueIsValid? = @( $true, $false, $false, $true )

$ValueIsValid?[0]
# old behaviour? gets `$true`
# new behaviour? gets nothing, because the `?[0]` is interpreted as a null-conditional access.

Ce comportement serait déjà en rupture avec les modifications proposées. Je préférerais une pause cohérente et nette à une pause déroutante qui nécessite une explication d'une demi-page pour lister toutes les exceptions possibles et quand et où ? n'est soudainement pas valide, et où il est toujours.

@KirkMunro si PowerShell 7 ou version ultérieure offre des fonctionnalités convaincantes dont les entreprises ont besoin, tout en prenant en charge les fonctionnalités dont elles ont besoin, elles utiliseront ces versions. Cela est particulièrement vrai si PowerShell 7 est installé avec le système d'exploitation.

Ayant travaillé dans quelques Fortune 50 avec certaines bases d'employés se chiffrant par centaines de milliers, même s'éloigner de ce qui était par défaut sur le système d'exploitation était un défi (c'est-à-dire passer à la v5.x). Je n'ai encore vu aucun endroit adopter Core ; ils préfèrent simplement passer à Python pour une compatibilité croisée. L'activation des fonctionnalités optionnelles de Windows était également une tâche assez rare.

Je pense que les entreprises travaillent avec ce qu'elles ont et la base de connaissances de leurs employés plutôt que de rechercher de nouvelles technologies ou des versions linguistiques pour résoudre leurs problèmes. Certains seraient parfaitement satisfaits de rester sur la v2 pour toujours et de ne jamais toucher les cmdlets Win10 / Server16 qui facilitent considérablement la vie.

Mon point avec tout cela, c'est que ces fonctionnalités ne sont pas dans le vide. Si vous rendez une langue plus ergonomique, elle verra une plus grande adoption par les personnes intéressées par l'outil pour résoudre plus rapidement les problèmes qu'elles rencontrent. (Voir: C # et la croissance de la popularité avec des fonctionnalités de langage plus / meilleures)

En ce qui concerne les variables se terminant par ? - cela pourrait être un changement de rupture significatif à cause de la variable automatique $? .

@lzybkr Je soupçonne que le meilleur cas pour traiter cela est un cas spécial comme ce qui existe $^ et $$ .

@lzybkr @ TheIncorrigible1 Autant que je me souvienne, _toutes_ ces variables sont explicitement casse spéciale dans le tokenizer. $^ _already_ n'est pas un nom de variable valide. Le tokenizer a des cas particuliers pour tous ceux-ci avant de commencer à rechercher des noms de variables standard.

La seule solution ici est d'utiliser ¿ :

$ idiot? ¿= 1

Je ne sais pas Steve, je suis fermement dans la foule interrobang sur celui-ci.

$silly?‽=1

@lzybkr - à ma connaissance $? $$ et $^ sont traités d'une manière spéciale.

https://github.com/PowerShell/PowerShell/blob/8b9f4124cea30cfcd52693cb21bcd8100d39a796/src/System.Management.Automation/engine/parser/tokenizer.cs#L3001 -L3004

Pour résumer, nous avons ces quatre options

  • Grand changement de rupture - ne pas autoriser ? dans les noms de variables.
  • Préférez ?. comme opérateur. Cela signifie que les noms de variables se terminant par ? doivent utiliser la syntaxe ${variablename} . Encore un changement de rupture.
  • Préférez les vieux comportements. Cela signifie que pour utiliser ?. et ?[] , ${variablename}?.property doit être utilisé. Aucun changement de rupture, mais rend l'utilisation des nouveaux opérateurs maladroite.
  • N'implémentez pas les nouveaux opérateurs.

Personnellement, je ne préfère pas le premier et le dernier.

Il s'agit d'un changement de version majeur. Il n'est pas déraisonnable que cela change ici, je pense.

Je pense qu'un point important à souligner est que la version principale est incrémentée pour signaler la disponibilité à remplacer Windows PowerShell, c'est-à-dire qu'elle indique la compatibilité et non la rupture. D'après l' annonce originale :

Notez que la version majeure n'implique pas que nous apporterons des changements significatifs.

Les options 1 et 2 ne sont-elles pas les mêmes? Ou les variables seraient-elles encore autorisées à utiliser ? dans le cas où il n'y aurait pas d'opérateur de fusion nul ou ternaire qui les suivrait?

Si tel est le cas, je pense que nous pourrions avoir beaucoup de mal à gérer la logique de tokenisation / analyse sans beaucoup de retour en arrière. Cela peut entraîner une dégradation des performances lorsque les variables se terminent par ? .

Compte tenu de ce que je peux voir, l'option 2 semble être la préférence générale, je ne suis pas vraiment sûr de comprendre la réticence à faire le changement décisif ici. Faire de cette façon découragera activement l'utilisation de ? dans les noms de variables de toute façon, simplement en introduisant des scénarios qu'ils ne sont pas utilisables sans inclure le nom de la variable.

Je pense que c'est un changement assez mineur car les changements de rupture vont, et avoir une rupture dans la cohérence de ce qui peut et ne peut pas être utilisé dans un nom de variable est probablement la pire option, à mon avis.

Ces choses devraient avoir des règles claires qui s'appliquent à presque toutes les situations. C'est actuellement le cas. Nous proposons de brouiller les eaux ici et de rendre le comportement _less_ clair. Je ne vois rien de bon en sortir, sauf peut-être que les noms de variables contenant ? deviennent moins utilisés simplement parce qu'ils sont plus difficiles à utiliser dans certains scénarios - ce qui nous ramène (effectivement) à l'option 1 par défaut, presque ... donc je ne vois aucune raison particulière de ne pas faire la pause maintenant et d'éviter simplement le comportement ambigu.

@ vexx32 Il y a une légère différence entre 1 et 2.

Pour # 1, nous interdisons l'utilisation de ? dans les noms de variables tous ensemble. Cela signifie que $x? = 1 , $x?? = 1 $x?x?x = 1 ne sera pas analysé.

Pour # 2, $x? = 1 est toujours valide mais $x?.name équivaut à ${x}?.name . Cela ne casse que les noms de variables avec ? à la fin, qui accèdent aux membres. Ainsi, $x? = 1 , $x?? = 1 $x?x?x = 1 serait toujours valide.

Ouais, je serais un peu préoccupé par la tokenisation des frais généraux là-bas. Cela pourrait valoir la peine d'implémenter les deux possibilités et de faire quelques tests sur un script qui utilise assez fortement des noms de variables similaires.

Ma préférence est définitivement l'option 1 ... un changement de rupture unique est, pour moi du moins, beaucoup plus préférable que d'avoir à gérer les incohérences dans la façon dont cela peut être analysé dans le futur.

Si tel est le cas, je pense que nous pourrions avoir beaucoup de mal à gérer la logique de tokenisation / analyse sans beaucoup de retour en arrière. Cela peut entraîner une dégradation des performances lorsque les variables se terminent par?.

Je partage cette inquiétude quant à cette possibilité. Avoir ? comme séparateur de jetons me semble parfois une ligne dentelée dans la langue.

Si tel est le cas, je pense que nous pourrions avoir beaucoup de mal à gérer la logique de tokenisation / analyse sans beaucoup de retour en arrière. Cela peut entraîner une dégradation des performances lorsque les variables se terminent par?.

Cela dépend de la manière dont vous le mettez en œuvre. Tant que vous adoptez une approche anticipée plutôt qu'une approche tokenize puis back-up, tout devrait bien se passer. Vous pouvez regarder à l'avance quels caractères seront les prochains lorsque vous rencontrez un ? dans un nom de variable, et prendre une décision sur la façon dont vous voulez "encapsuler" le jeton de variable en fonction de la suite. Cela ne pose pas beaucoup de problèmes et ne devrait pas nécessiter de retour en arrière ou entraîner des dégradations notables des performances.

@ PowerShell / PowerShell-Committee a examiné celui-ci aujourd'hui, nous avons quelques réflexions:

  • Peu importe ce que nous faisons, nous allons faire une analyse de notre corpus de scripts pour voir à quelle fréquence les gens utilisent ? dans les noms de variables
  • Certains d'entre nous ont une hypothèse (que d'autres aimeraient valider) selon laquelle les utilisateurs qui utilisent ? dans leurs noms de variables peuvent être des utilisateurs moins avancés (comme nous sommes d'accord dans cette salle, nous nous en tenons à l'écart car des problèmes potentiels qui pourraient survenir). D'un autre côté, toute personne utilisant la fonctionnalité décrite ici sera capable de comprendre une syntaxe légèrement plus compliquée (comme ${foo}?.bar ). Par conséquent, nous préférons l' option 3 car elle évite de casser les changements sur ces utilisateurs moins expérimentés. (Mais encore une fois, nous le validerons par la première puce.)
  • @ daxian-dbw a soulevé un bon point sur le fait qu'il est plus difficile de trouver toutes les références de variables lorsque les scripteurs mélangent l'utilisation de $foo et ${foo} . Cependant, nous avons convenu que cela pouvait être corrigé dans les outils (comme l'extension VS Code PowerShell), et les utilisateurs comme @JamesWTruher qui utilisent des éditeurs comme Vim peuvent facilement faire correspondre les deux avec leur syntaxe de recherche.

plus difficile de trouver toutes les références de variables lorsque les scripteurs mélangent l'utilisation de $ foo et $ {foo}

Cela dépend si l'AST différencie le nom de la variable selon qu'il a vu les accolades. Je soupçonne que tout outil utilisant le PowerShell AST n'aura aucun problème avec les accolades ici.

Mais pour les regex, cela signifie certainement que vous devez être plus conscient: varname -> \{?varname\}?

@rjmholt J'ai fait une analyse ici . Une ventilation rapide: sur près de 400 000 scripts avec plus de 22 000 000 noms de variables (non uniques), il n'y avait que ~ 70 variables uniques qui se terminaient par ? .

Merci, @mburszley - pour moi, cela en fait un Bucket 3: Changement de {...} est très malheureux, parallèlement au besoin malheureux de $(...) autour de exit / return / throw déclarations dans le contexte de && et || .

Pour emprunter le raisonnement à cette question:

Si nous forçons l'utilisation de {...} autour des noms de variables juste pour que vous puissiez utiliser ?. :

  • Les nouveaux utilisateurs ne s'attendront pas à avoir besoin de {...} et ne sauront pas nécessairement que _it_ est ce qui est requis lorsque ce qui suit échoue (éventuellement _undetected_, sauf si Set-StrictMode -Version 2 ou plus est en vigueur): $o = [pscustomobject] @{ one = 1 }; $o?.one

  • Même une fois que les utilisateurs _do_ savent qu'il faut {...} :

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

Ce problème a été marqué comme résolu et n'a eu aucune activité pendant 1 jour . Il a été fermé à des fins d'entretien ménager.

@rjmholt , vous citant de https://github.com/PowerShell/PowerShell/issues/10967#issuecomment -561843650:

ne pas casser la façon dont nous analysons la syntaxe valide existante était la bonne voie à suivre. Encore une fois, un changement, ce n'est pas seulement le cas où nous prenons la décision de soutenir un petit nombre de programmes sauvages - nous avons apporté de nombreux changements décisifs dans les cas où nous pensions que les avantages l'emportaient sur les inconvénients (ce n'est pas que je suis personnellement d'accord avec tous, ou que ceux-ci justifient ou non les autres). Le problème est que la modification d'un aspect du tokenizer ou de l'analyseur signifie que deux versions de PowerShell ne généreront plus le même AST pour certains scripts, donc deux PowerShells "verront" le même script différemment. Cela signifie que nous ne pouvons même pas lire la syntaxe de la même manière, il n'y a donc pas de règle PSScriptAnalyzer que vous pouvez écrire pour détecter d'éventuels problèmes; PSScriptAnalyzer verra une syntaxe différente d'une version de PowerShell à la suivante.

Contrairement à C #, PowerShell ne peut pas précompiler une syntaxe différente dans un format compatible pour une exécution ultérieure, ce qui signifie qu'une modification syntaxique est liée à l'exécution. Une fois que PowerShell fait une rupture syntaxique, nous réduisons le nombre de scripts pouvant fonctionner avec différentes versions, ce qui signifie que les utilisateurs sont obligés d'écrire deux scripts, ce qui est un problème sérieux pour un shell et un langage de script. PowerShell est censé être suffisamment dynamique pour contourner toutes les différences avec la logique à l'intérieur d'un script, mais la syntaxe est la seule chose statique non négociable que nous ayons. Et faire un changement de syntaxe où l'avant et l'après sont valides est particulièrement pernicieux, car il n'y a pas de moyen simple de le détecter, il n'y a pas d'avertissement pour cela et même après son exécution dans les deux environnements, les utilisateurs peuvent ne pas savoir qu'un comportement différent s'est produit.

En général, je peux comprendre que de tels changements peuvent être très problématiques et ne devraient être faits que si les avantages l'emportent sur les inconvénients, dont un facteur important est la quantité de code existant.

nous réduisons le nombre de scripts pouvant fonctionner avec différentes versions
ce qui signifie que les utilisateurs sont obligés d'écrire deux scripts

Nous parlons ici d'une _nouvelle_ fonctionnalité syntaxique ( ?. ), donc par définition, les scripts qui l'utilisent _cannot_ (significativement) s'exécutent sur des versions plus anciennes - sauf si vous ajoutez spécifiquement des conditions qui fournissent des chemins de code compatibles avec les versions héritées, mais cela ne vaut guère la peine - vous vous en tiendrez alors aux fonctionnalités héritées.

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

  • ? n'aurait jamais dû être autorisé en tant qu'élément d'un identifiant _ sans l'inclure dans {...} _.

  • Étant donné que pouvoir le faire est inattendu et probablement même inconnu pour beaucoup, ces noms de variables sont extrêmement rares dans la nature, par 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 sont conscients qu'ils ne devraient _pas_ supposer que d'autres langues prennent en charge la même chose.

Donc, de manière 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), en fonction du 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 du manifeste de module).

Dans l'ensemble, il s'agit pour moi 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, au contraire, en évitant les maux de tête persistants dus à un comportement inattendu).

@ mklement0 nous

Ça a l'air bien, @ SteveL-MSFT - s'il vous plaît voir # 11379.

J'encourage tout le monde ici à montrer à nouveau son soutien (ou, halètement, non-soutien) là-bas.

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