Powershell: Vorschlag: Implementieren Sie eine nullkoaleszierende, nullbedingte Zuweisung (null-soaking) und eine nullbedingte Zuweisung

Erstellt am 2. März 2017  ·  71Kommentare  ·  Quelle: PowerShell/PowerShell

Null-Coalescing und Null-Conditonal-Zugriff (Null-Soaking) wären praktische Ergänzungen zur Sprache.

_Update_: @BrucePay schlägt zusätzlich eine nullbedingte Zuweisung mit ?= - siehe Kommentar unten .

Zum Beispiel anstatt zu schreiben:

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

man könnte schreiben können:

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

Re null-bedingter Zugriff: Wenn Set-StrictMode OFF ist (Standardeinstellung), können Sie einfach $varThatMayBeNull.Name - keine spezielle Syntax erforderlich; Wenn jedoch Set-StrictMode -Version 2 oder höher in Kraft ist, würde $varThatMayBeNull.Name _break_ und hier ist der nullbedingte Operator ( ?. ) hilfreich, um die explizite Absicht zu signalisieren, das zu ignorieren $null auf prägnante Weise.


Offene Frage :

$varThatMayBeNull?[42] behandelt den Fall, in dem die Variable $null , aber wenn dies nicht der Fall ist, muss ein Array-Element mit dem angegebenen Index _ existieren_.

Es wäre daher auch hilfreich , _indexing_ null-bedingt zu .ElementAtOrDefault() ).

Die zwei grundlegenden Optionen sind:

  • Überlegen Sie sich eine zusätzliche Syntax, die explizit die Absicht signalisiert, einen nicht vorhandenen Index zu ignorieren:

    • Die Frage ist, welche Syntax hierfür zu wählen ist, da ?[...] und [...]? aufgrund von Mehrdeutigkeiten keine Option sind.
    • Vielleicht [...?] , aber das scheint unangenehm.
  • Verlassen Sie sich auf das vorhandene Verhalten beim Zugriff auf nicht vorhandene Indizes, wie dies durch die Einstellung Set-StrictMode impliziert wird - siehe Tabelle unten .


Verwandte: Implementieren Sie ternäre Bedingungen

Issue-Enhancement Resolution-Fixed WG-Language

Hilfreichster Kommentar

@rjmholt Ich habe eine Analyse über hier . Eine kurze Aufschlüsselung: Von fast 400.000 Skripten mit mehr als 22.000.000 Variablennamen (nicht eindeutig) gab es nur ~ 70 eindeutige Variablen, die mit ? endeten.

Alle 71 Kommentare

@ mklement0 Es scheint, dass das zweite Beispiel ohne "?"
Vielleicht zu name() wechseln?

@iSazonov : Guter Punkt, aber es funktioniert nur ohne ? sei denn, Set-StrictMode -Version 2 oder höher ist _not_ in Kraft - ich habe den ersten Beitrag aktualisiert, um dies zu verdeutlichen.

Ich denke, syntaktischer Zucker ist etwas, das Powershell gebrauchen könnte, das andere Sprachen genießen. +1 auf den Vorschlag.

Betrachten Sie die folgenden Beispiele aus anderen Sprachen:

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

sogar

a = b if b else c

ist besser als

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

und oft muss man mit dem zusätzlich wortreich klären

a = (if (b -ne $ null) {b} else {c})

Man fühlt sich schmutzig und verprügelt.

Ich habe das heute als Workaround gemacht.

`` `Powershell
$ word = ($ null, "zwei", "drei"). Wobei ({$ _ -ne $ null}, "First")
`` ``

Ich benutze ein ähnliches Muster:

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

@kfsone In Ihrem Beispiel gibt es einen kleinen Fehler $a=(if ($b -ne $null) { $b } else { $c }) . Es sollte $a=$(if ($b -ne $null) { $b } else { $c }) aber die einzige Version von PowerShell, für die $( ) erforderlich war, war Version 1. Ab Version

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

@bgshacklett Meinst du nicht $word=($null,'two')[$null -ne 'three'] ?

Es ist ein bisschen bedauerlich, dass dies von 6.1 auf 6.2 auf "Future" übergegangen ist.

@ TheIncorrigible1 Nein, wenn Sie das, was ich oben hinzugefügt habe, kopieren und einfügen, sollten Sie sehen, dass der Wert von $word auf "zwei" gesetzt ist. In dieser Antwort zum Stapelüberlauf finden Sie weitere Details, in denen ich das Muster zum ersten Mal gesehen habe:
https://stackoverflow.com/a/17647824/180813

Während perleske Hack-arounds mich vor 20 Jahren ansprechen, der einen Schebang geschrieben hat, der einen RIPE-DB-Benutzer- oder Organisationsdatensatz registriert und / oder abgefragt hat, ist das, was ich mir von Powershell erhoffe, etwas, das meine Kollegen dazu ermutigt, die Sprache zu verwenden anstatt ihnen Angst zu machen.

Mein Lackmustest lautet: Würde ich das um 3 Uhr morgens am Neujahrsmorgen über mein Tablet lesen wollen, während ich mit dem CEO am Telefon rumhängt und mich anschreie, wie viele Millionen Dollar wir pro Sekunde verlieren.

(Abgesehen davon: Dies war nur eine lose Übertreibung einer tatsächlichen Erfahrung, bis ich bei Facebook arbeitete und von einem dringenden schnellen Leck zurückkam, um zu erfahren, dass in den 2 Minuten, in denen ich weg war, mehr Menschen als die holländische Bevölkerung leer geworden waren Newsfeed. Es war nicht mein Code und der Fehler war eine winzige Änderung der Semantik von return x vs return (x) im c ++ - Standard für sehr spezifische Vorlagenfälle Frist, eine volle Blase und das Schicksal jedes Clogs, der die Katzenbilder einer niederländischen Person auf der Schulter trägt ??? "klang nicht so cool)

Jep. In PS sind einige nette Tricks möglich, die zur Not großartig sind oder wenn Sie eine einmalige Kurzschrift benötigen.

Für wartbaren Code sollten wir idealerweise explizite Null-Koaleszenz-Operatoren wie C # haben. Das Hauptproblem für mich ist - was verwenden wir für diese? ? ist bereits auf Where-Object (so sehr ich es auch gerne löschen würde, es wird sehr häufig verwendet). Wohlgemerkt, % ist auf ForEach-Object aber das behindert die Moduloperationen nicht, so dass theoretisch zumindest ? ein Null-Koaleszenz-Operator sein könnte fein; es würde nur als solches in Ausdrücken interpretiert, in denen Where-Object sowieso nicht wirklich gültig ist.

@ vexx32 :

Zumindest _syntaktisch_ ?? sollte in Ordnung sein, da es sich um den Ausdrucksmodus handelt, während ? als Befehl [Alias] nur im Argumentmodus erkannt wird.
Ich bin nicht sicher, ob die Wiederverwendung des Symbols Verwirrung stiftet, aber es wäre nicht das erste Mal, dass ein Symbol in verschiedenen Kontexten doppelte Aufgaben erfüllt.

Überraschenderweise wäre die Verwendung von ?. und ?[] für das Null-Einweichen technisch eine bahnbrechende Änderung, da PowerShell derzeit ? als nicht initiales Zeichen in einem Variablennamen zulässt.

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

Ich hoffe jedoch, dass dies als Änderung von Bucket 3: Unwahrscheinliche Grauzone angesehen wird.

Ich kann nicht sagen, dass ich jemals jemanden gesehen habe? in einem Variablennamen ... Ich auch nicht, weil es wahrscheinlich falsch verstanden wird. Aber ja, hoffentlich sollte das perfekt nutzbar sein.

Ich vermute, es ist etwas spät, dies anzusprechen, aber Bash hat dies (und einige andere Fälle) mit seinen Funktionen zur Parameterersetzung behandelt: https://www.tldp.org/LDP/abs/html/parameter-substitution.html.

Obwohl es aufgrund der Vielzahl von Dingen, die damit gemacht werden können, ein Bär sein kann, ist es unglaublich mächtig. Ich verstehe, dass es aufgrund der Art und Weise, wie PowerShell geschweifte Klammern mit Variablen verwendet, nicht möglich wäre, diese exakte Notation zu verwenden, und dass sie auch nicht unbedingt zum allgemeinen Sprachgefühl passt, aber es scheint ein nützlicher Datenpunkt zu sein.

@bgshacklett :

Ja, die Parametersubstitution ist mächtig, aber leider ist es nicht nur ein Bär zum Lernen, sondern auch zum Erinnern.

Während Bashs Eigenschaften oft interessant sind, ist ihre syntaktische Form oft geheimnisvoll, schwer zu merken und passt nicht gut zu PowerShell.

_Brace Expansion_ (z. B. a{1,2,3} in bash Erweiterung auf a1 a2 a3 ) ist ein Beispiel für eine interessante Funktion, deren Ausdruckskraft ich gerne in PowerShell sehen würde, aber mit PowerShell-angemessen Syntax - siehe # 4286

Ich stimme vollkommen zu. Ich habe es eher als Beispiel dafür angeführt, wie dieses Problem anderswo gelöst wurde, als als exakte Lösung.

Es gibt noch einen anderen Operator, der möglicherweise berücksichtigt werden muss:

$x ?= 12

Das würde $x wenn es nicht gesetzt ist (existiert nicht). Dies ist Teil des "Initialisierungsmusters", das in herkömmlichen Sprachen nicht üblich ist, aber für Sprachen mit dynamischem Gültigkeitsbereich wie Shells, Make-Tools usw. ist es ziemlich üblich, ein Skript zu haben, das einen Standard festlegt, wenn der Benutzer ihn nicht angegeben hat . (Obwohl in der Tat Parameterinitialisierer ziemlich weit verbreitet sind.)

Erweiterung auf Eigenschaften:

$obj.SomeProperty ?= 13

würde eine Notiz-Eigenschaft SomeProperty für das Objekt hinzufügen und initialisieren, wenn es nicht vorhanden wäre.

Und - zum Spaß - noch eine Variante zum Initialisieren einer Variablen mit -or :

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

$x ?= 12 klingt nach einer großartigen Idee.

Mir ist der Gedanke gekommen, dass wir wahrscheinlich alle diese Operatoren nicht nur anwenden sollten, wenn die LHS nicht existiert, sondern auch, wenn sie existiert, aber zufällig $null (wobei [System.Management.Automation.Internal.AutomationNull]::Value wie $null behandelt wird

Hinzufügen und Initialisieren einer Notizeneigenschaft SomeProperty

In diesem Sinne ist $obj.SomeProperty ?= 13 für mich _nur_ sinnvoll, wenn .SomeProperty existiert und $null , da Sie selbst bei regulären Zuweisungen keine impliziten Eigenschaften erstellen können (im Gegensatz dazu für _hasthables_ the implizite Eintragserstellung ist sinnvoll).

Alle besprochenen Bediener müssen die LHS von der Existenzprüfung im strengen Modus ausnehmen.

Ich frage mich, welche Absichten / Gründe dahinter stehen, warum der strikte Modus Sie daran hindert, auf eine Eigenschaft zuzugreifen, die nicht existiert. Ist die Absicht, Tippfehler wie $x.pretnd zu fangen? Ist die Absicht, Annahmen wie assert(x != null) zu überprüfen? Ist die Absicht, die versehentliche Weitergabe von $null weiter unten in Ihrem Code zu blockieren?

Das Null-Einweichen (?.) ist hilfreich, um die explizite Absicht zu signalisieren, das $ null auf prägnante Weise zu ignorieren.

Ist das nicht das, was . bereits im nicht strengen Modus signalisiert? Wenn Sie streng sein wollten, hätten Sie zuerst prüfen können, ob .Name vorhanden ist. Wenn Sie nicht zuerst prüfen, haben Sie bereits ausdrücklich darauf hingewiesen, dass die Prüfung für Sie nicht wichtig ist.

Wenn StrictMode einen Zweck hat, bei dem der Zugriff auf eine nicht vorhandene Eigenschaft und die Rückgabe von $null verboten ist, gilt nicht dieselbe Argumentation für ?. , und dies sollte aus demselben Grund dieselbe Ausnahme auslösen . Wenn nicht, warum nicht?

Mit Null-Coalescing könnten Sie schreiben:

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

Wird es schnell empfohlen oder idiomatisch, immer ?. für jede Eigenschaftsreferenz zu verwenden, weil es sich "wie . verhält und keine Ausnahmen für Personen auslöst, die den strengen Modus verwenden"?

Ist der eigentliche Wunsch nach einem konfigurierbaren Strict-Modus mit variablen Einstellungen, so dass Sie beispielsweise eine Deklaration am oberen Rand Ihres Skripts # StrictMode SkipMemberExistenceCheck oder ein Escape-Hatch-Attribut für die Angabe eines Blocks von unstrict code haben könnten allgemein? [Ich vermute, der Wunsch ist eine knappe Syntax im C # -Stil, aber Sie wissen, was ich meine]

Danke für die Gedanken, @HumanEquivalentUnit.

Ist die Absicht, Tippfehler wie $x.pretnd zu fangen?

Ich kann nicht mit der Entwurfsabsicht sprechen, aber das macht für mich Sinn - analog zu dem, was Set-StrictMode -Version 1 für _variables_ (nur) tut.

Bei Variablen geht es um ihre Existenz, nicht darum, ob der Wert zufällig $null , und die Überprüfung der Existenz von Eigenschaften folgt demselben Muster.

Ich denke, es ist das Beste, was eine dynamische Skriptsprache erreichen kann, um Fehler zu finden, die eine statisch typisierte kompilierte Sprache zur Kompilierungszeit melden würde.


Ist das nicht was? Signale bereits im nicht strengen Modus? Wenn Sie streng sein wollten, hätten Sie zuerst nach .Name suchen können

Ja, aber im nicht strengen Modus verzichten Sie auf die oben genannten Existenzprüfungen, und das manuelle Testen ist offensichtlich ziemlich umständlich - und ausnahmslos langsamer als eine integrierte Funktion.

Indem Sie nicht zuerst nachgesehen haben, haben Sie bereits ausdrücklich darauf hingewiesen, dass die Prüfung für Sie nicht wichtig ist.

Der Punkt ist, dass Sie mit Set-StrictMode -Version 2 oder höher Folgendes erhalten:

  • der Vorteil der Überprüfung der Existenz von Mitgliedern _by default_
  • die Option, sich auf Anfrage mit .? abzumelden

Sie könnten eine Deklaration oben in Ihrem Skript # StrictMode SkipMemberExistenceCheck oder ein Escape-Hatch-Attribut haben, um einen Block von unstrict code allgemein anzugeben

Verwandte: Das aktuelle dynamische Scoping von Set-StrictMode ist problematisch; Informationen zur Implementierung eines _lexical_ strict-Modus finden Sie im RFC-Entwurf von @lzybkr: https://github.com/PowerShell/PowerShell-RFC/blob/master/1-Draft/RFC0003-Lexical-Strict-Mode.md

der Vorteil der standardmäßigen Überprüfung der Existenz von Mitgliedern

PS enthält Code, der die Mitgliederprüfung durchführt, und gibt $ null zurück, wenn sie nicht vorhanden sind. Dies ist standardmäßig ein Vorteil, den Sie auch vermeiden können, indem Sie Ihren eigenen Mitgliedsexistenztest mit $x.psobject.properties... schreiben, wenn Sie dies wünschen. StrictMode nimmt diesen Vorteil weg und verhindert, dass Existenzprüfungen geschrieben werden müssen. Anstatt eine gute Möglichkeit zu bieten, genau einen Existenztest für Mitglieder zu schreiben, bietet Ihnen ?. eine präzise Problemumgehung, um das zu erhalten, was . immer getan hat. Und wenn es darauf ankommt, dass das Mitglied existiert, müssen Sie dies immer noch separat codieren.

Aber das lässt mich fragen, was ist mit Methodenaufrufen:

$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()   -> ____  ?

Das heißt, ?. würde sich genauso verhalten wie . für die Suche nach Eigenschaften im nicht strengen Modus, würde sich jedoch anders verhalten als . für Methodenaufrufe im nicht strengen Modus, wodurch es nuanciert wird und nicht ein Drop-In-Ersatz. Bedeutet das, dass Sie bei Verwendung von ?. überhaupt nicht feststellen können, ob eine Methode aufgerufen wurde oder überhaupt nichts passiert ist? Eigenschaften können durch Getter-Methoden unterstützt werden, aber ich denke, es ist in DotNet üblich, dass Getter den internen Status nicht mutieren, aber normal für Methodenaufrufe, um den Status zu mutieren. Mit ?. Sie keine Ahnung, ob Sie den Status eines Objekts mutiert haben?

Ich frage mich, ob Sie die gewünschten und besseren Vorteile erzielen können, indem Sie ?? Lage versetzen, PropertyNotFoundException- und MethodNotFound-Ausnahmen direkt aus dem Ausdruck auf der linken Seite (aber nicht andere in Methoden hervorgerufene Ausnahmen) sowie $ zu verarbeiten Nullen und haben überhaupt keine ?. . z.B

$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

Und dann, anstatt ?. ein Mitglied anzurufen oder auf eine Eigenschaft zuzugreifen, könnte dies eine kurze Möglichkeit sein, zu fragen, ob ein Mitglied existiert, und einen [Bool] zurückzugeben.

Mit der gleichen Syntax von ?? und ?. könnten Sie mehr Situationen mit weniger verwirrenden Überlappungen bewältigen.

StrictMode nimmt diesen Vorteil weg und verhindert, dass Existenzprüfungen geschrieben werden müssen

Das Hindernis einer Person ist der Vorteil einer anderen Person:
Es hängt alles davon ab, was standardmäßig geschehen soll:

  • Wenn Sie sicher sind, dass Ihr Code keine Typos enthält, nutzen Sie auf jeden Fall das Standardverhalten (strikter Modus AUS), und Sie benötigen keine .? (für _Eigenschaftszugriff - siehe nächster Kommentar zu Methodenaufrufen und Indexierung).

    • Persönlich: Ich neige dazu, Set-StrictMode -Version 1 zu verwenden, um Tippfehler in _variablen_ Namen zu vermeiden, aber ich finde -Version 2 oder höher zu ärgerlich, hauptsächlich aufgrund von # 2798 (was ein Fehler ist, der unabhängig ist dieser Vorschlag).
  • Wenn Sie sicherstellen möchten, dass Sie (a) keine Eigenschaftsnamen falsch geschrieben haben und / oder (b) Ihr Code nicht versehentlich mit anderen Datentypen als den beabsichtigten ausgeführt wird, setzen Sie den strengen Modus auf Version 2 oder höher .

    • In der Tat macht es das gegenwärtig umständlich, diese Überprüfungen auf Verlangen zu beenden.
    • Genau aus diesem Grund wird hier die Einführung eines nullbedingten Zugriffs vorgeschlagen: um es einfach zu machen, sich bei Bedarf abzumelden.

Das explizite Testen der Anwesenheit eines Mitglieds ist in Wirklichkeit ein separater Anwendungsfall, der unabhängig vom geltenden strengen Modus eine Notwendigkeit sein kann.

Wie für Methodenaufrufe, die das OP nicht abdeckt:

_Method Calls_ (z. B. $varThatMayBeNull.Method() ) und _indexing_ (z. B. $varThatMayBeNull[$index] ) sind zwei Fälle, in denen sogar der strikte Modus deaktiviert oder in Version 1 von Vorteil sein kann, da beide Fälle derzeit _veränderlich_ einen Fehler verursachen, wenn Der Wert, auf den zugegriffen wird, ist $null .

Die Syntax ist dieselbe wie für Eigenschaften für Methoden - $varThatMayBeNull?.Method() - und analog für die Indizierung - $varThatMayBeNull?[$index] - wie in C #.

_Update_: Die Indizierung hat einen zweiten Aspekt, nämlich wenn die Variable nicht null ist, das Element am angegebenen Index jedoch nicht vorhanden ist (z. B. $arr = 0,1; $arr[2] ). Mit Strict Mode-Version 2 oder niedriger ergibt dies $null , aber in Version 3 oder höher verursacht es einen Fehler, und es wäre schön, wenn Sie diesen Fehler ebenfalls deaktivieren könnten. Die Syntax für diesen Fall stellt jedoch eine Herausforderung dar - siehe das aktualisierte OP, in dem derzeit das möglicherweise umständliche [...?] .

Und ja, ich würde einen solchen Zugriff auch für Methoden standardmäßig auf $null - wieder signalisieren Sie _explizit_, dass es in Ordnung ist, nichts zu tun, wenn das Objekt, auf das zugegriffen wird, $null oder ist wenn kein solches Array-Element vorhanden ist.

Beachten Sie, dass C # im zweiten Sinne keine nullbedingte Indizierung hat.

Es hat eine nullbedingte Indizierung, nur nicht ganz so, wie Sie es vorschlagen. C # erlaubt (ich bin mir ziemlich sicher, zumindest ...) array?[0] das das übliche Problem "Index in null Array / Sammlung" umgeht und nur null zurückgibt.

Aber ja, ich stimme zu, dass dies eine gute Idee ist. Dies erspart uns die Ausnahmebehandlung und hält den Code ziemlich klar und präzise.

@ vexx32 , das ist ein Aspekt der nullbedingten Indizierung: Wenn array in array?[0] null , wird die Indizierungsoperation ignoriert - C # hat das auch, wie Sie angeben.

Ich habe (Update: auch) über den anderen Aspekt der nullbedingten Indizierung gesprochen: Der Fall, in dem array in array?[0] _not_ null aber es _ das Element am Index 0 _ das gibt es nicht.

Letzteres kann meines Wissens in C # nicht ignoriert werden, aber ich denke, es wäre auch nützlich.

Können Sie sich eine Terminologie vorstellen, um diesen beiden Aspekten unterschiedliche Namen zu geben?

Der Code aus einem anderen JavaScript-Problem würde von $_.Description[0].Text auf $_?.Description[0?]?.Text steigen, was ich nicht schön finde. und mein anderer Vorschlag, wie sich ?? verhalten könnte, würde es auf $_.Description[0].Text ?? was subjektiv schöner ist und - wenn möglich zu implementieren - Fehler an jedem Suchpunkt in der Kette auf einmal behandeln würde und lassen Sie trotzdem auswählen, was standardmäßig geschehen soll, und haben nach Belieben einen anderen Fallback, anstatt auf nur $null .

Abgesehen davon, hätte diese ?. -Syntax ein Analogon für statische Eigenschaften und Methoden, dh $t = [int]; $t::MaxValu; $t::Pars("1") , würde das zu ?: oder ?:: ?

Was wäre das gewünschte Verhalten für die Array-Indizierung mit mehr als einem angegebenen Index? $array[0,4?,1,2] wo jeder scheitern darf oder $array[0,4,1,2?] mit nur dem gesamten Los, das erfolgreich sein oder scheitern darf?

Ich muss zuerst einen Schritt zurücktreten, weil mir klar wird, dass ich Aspekte zusammengeführt habe, die es wert sind, zumindest konzeptionell getrennt zu werden:

  • _Null-value_-bedingter Element- oder Indexzugriff wie in C #:

    • Wenn ein Wert, auf den zugegriffen wird, $null , ignorieren Sie Versuche, auf seine Mitglieder zuzugreifen oder ihn zu indizieren, und bewerten Sie ihn mit $null .
  • _Member-Existenz_-bedingter Mitglied- oder Indexzugriff, spezifisch für PowerShell:

    • Wenn ein Wert, auf den zugegriffen wird, _non- $null _ ist, ignorieren Sie Versuche, auf nicht vorhandene _Mitglieder_ (Eigenschaften, Methodenaufrufe, Indizierung) zuzugreifen, die nicht vorhanden sind.

Hinweis: Der Kürze halber verwende ich _member_ hier etwas locker, um auch _Elemente_ von Objekten zu erfassen, bei denen es sich zufällig um Sammlungen handelt, auf die mit _indexing_ anstatt mit Punktnotation zugegriffen wird.

Wenn Sie sicher sind, dass Ihr Code keine Tippfehler enthält - nutzen Sie auf jeden Fall das Standardverhalten (strikter Modus AUS) - und Sie brauchen keine.? (für den Zugang zu Eigentum

@ mklement0 Ich denke, Sie diskutieren aus der Sicht " Eine Person verwendet den strengen Modus, um ihren eigenen Code zu verbessern " und ich aus der Sicht "Eine andere Person kann meinen Code im strengen Modus ausführen. Welche Änderungen würden dazu führen, dass mein Code auch für sie funktioniert?" "und das führt mich zu anderen Überlegungen. Mit ?. wäre es so bequem, es anstelle von . und den Code auch im Strict-Modus funktionieren zu lassen, so dass ich ihn genauso gut überall verwenden kann. Ich verliere nichts und gewinne Kompatibilität. Ich befürchte, dass der gesamte PowerShell-Code auf diese Weise hässlich wird, da er in mehr Fällen "funktioniert".

Es handelt sich jedoch nicht um einen Drop-In-Ersatz, da dadurch die Suche nach fehlgeschlagenen Methodenaufrufen im nicht strengen Modus und die Suche nach fehlgeschlagenen Eigenschaften im strengen Modus stummgeschaltet werden. Dies fügt der Suche nach Mitgliedern eine fummelige Nuance hinzu, eine unglaublich häufige Operation. Es hilft niemandem, der von strengen Modusprüfungen profitieren möchte, indem es das Boilerplate einfacher macht. Es hilft nicht genug Menschen in genug Situationen, für die Komplexität, die es hinzufügt. Und es ist zu bequem, um den Code kompatibler zu machen. Ich denke nicht, dass "Ignorieren, wenn Sie es nicht wollen" stark genug ist, um es in Schach zu halten.

PowerShell kann Dinge tun, die C # nicht tut, wie das Festlegen automatischer Variablen oder einen Präzedenzfall dafür, dass Ausnahmen hinter die Kulissen geworfen und zum Schweigen gebracht werden. Es muss einen besseren Ansatz geben, der die Suche nach Mitgliedern überhaupt nicht komplexisiert, sondern das Boilerplate für Sicherheitsüberprüfungen im strengen Modus vereinfacht, damit Personen, die die Überprüfungen verwenden möchten, ein einfacheres Leben haben und Personen, die sich über die Überprüfungen geärgert haben, auch ein einfacheres Leben haben.

@HumanEquivalentUnit Wie bringt es diese Dinge zum Schweigen? Stattdessen müssten Sie zuvor eine Menge Ausnahmebehandlungen und Nullprüfungen schreiben:

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

v.

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

Und dieser Fall ist nicht ungewöhnlich. Oder Sie werfen einfach $ErrorActionPreference = 'Stop' und wickeln das Ganze in try/catch , um die Nullprüfung zu vereinfachen, was ein schlechtes Muster ist (ausnahmegesteuerte Logik).

Dies ist auch die Zukunft der Sprache. Es ist nicht so, als würden wir zu 5.1 zurückkehren und Dinge ändern. Wenn Sie mehr Anwender wünschen, müssen Sie das Lesen von Code erleichtern , was meiner Meinung nach bei diesem Vorschlag der Fall ist.

@ mklement0 Ich denke, Sie diskutieren aus der Sicht "_eine Person, die den strengen Modus verwendet, um ihren eigenen Code zu verbessern_" und ich aus der Sicht "_jemand anderes kann meinen Code im strengen Modus ausführen. Welche Änderungen würden meinen Code auch für sie funktionieren lassen? _ "

Sprechen wir über das Äquivalent "set -euo pipefail" (bash strict mode)?

a- Beschränken Sie sich auf variable Suchvorgänge (obwohl ich nicht verstehe, warum eine einfache Nullprüfung von Mitgliedersuchen eine schlechte Sache wäre, ist die tatsächliche Mitgliedersuche viel teurer als if (result is null) ).
b- Verwenden Sie [Strict] für Bereiche / Codeblöcke, um den Parser anzuweisen, sie als solche zu behandeln.
c- Strenge basiert auf dem Umfang: Code, der nicht als streng markiert ist, ist nicht streng.

Wenn ich strengen Code geschrieben habe, der bei der Verwendung fehlschlägt, hat einer von uns einen Fehler gemacht. Entweder habe ich auf eine fehlende Variable in Code verwiesen, den ich nie getestet habe, oder Sie haben meine schlecht gestaltete API falsch verstanden, die von der Existenz von Variablen abhängt, die nicht an meine Funktion übergeben wurden, und Sie haben eine Variable nicht ausgefüllt, von der ich erwarte, dass sie ausgefüllt wird. .

# 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.

Die "Log" -Funktion wurde nicht als streng markiert, sodass sie sich nicht über den Tippfehler beschwert

🤔 Nun, da Sie es erwähnen, wäre ein [Strict()] -Attribut eine fantastische Möglichkeit, den strengen Modus in einer auf den Bereich beschränkten Weise zu implementieren. Das muss in diesem anderen Issue-Thread zu Fragen des strengen Modus erwähnt werden. Ich werde das ausgraben und hierher zurück verlinken ...

@ TheIncorrigible1 " Wie bringt es diese Dinge zum Schweigen? " Im nicht strengen Modus $null.x schweigt, $null.x() ist eine Ausnahme. Wenn ?. wie besprochen ist, schweigt $null?.x , $null?.x() schweigt.

Sie hätten also ein . das wie C # ?. funktioniert, außer im Strict-Modus, wo es Ausnahmen auslöst. Dann hätten Sie ein ?. das im strengen Modus wie C # ?. und wie PowerShells . im nicht strengen Modus funktioniert, aber anders funktioniert als PowerShells . im nicht strengen Modus für Methodenaufrufe. Was für eine schreckliche Kombination (und eine Kombination, bei der ?. in mehr dieser Szenarien eindeutig besser und nützlicher ist).

Stattdessen müssten Sie zuvor eine Menge Ausnahmebehandlungen und Nullprüfungen schreiben: $prop = $item?.Method().PropIwant ?? 'PropActionFailed'

Ihr Methodenaufruf könnte $ null auslösen oder zurückgeben und PropIWant könnte fehlen. Sie müssten noch schreiben:

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

vs mit meinem vorgeschlagenen ?? (wenn es möglich war zu bauen), und keine Notwendigkeit für ?. , und es deckt mögliche Fälle von Methodenausnahmen ab, falls alles, was Sie interessiert, "Erfolg oder nicht" ist. und keine detaillierte Fehlerbehandlung.

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

Wenn Sie mehr Anwender wünschen, müssen Sie das Lesen von Code erleichtern, was meiner Meinung nach bei diesem Vorschlag der Fall ist.

Wie oft geben Sie . in PowerShell ein? Wie oft möchten Sie neuen Benutzern erklären, was der Unterschied zwischen . und ?. und ihnen sagen, dass sie den Unterschied jedes Mal berücksichtigen müssen, wenn

"Oh, wie kam es dazu?" "Nun, in C # . eine Ausnahme für vermisste Mitglieder, also haben sie ?. erfunden, was nicht der Fall war. Das war großartig, also haben sie das standardmäßig in PowerShell gemacht, die . wirft nicht. Dann erfanden sie den Strict-Modus, der . bringt, sich wie C # zu verhalten und zu werfen, aber nur in diesem Zusammenhang. Aber die Art, Mitglieder manuell zu überprüfen, war wirklich wortreich und lästig und niemand wollte sie eingeben. Anstatt dieses Problem direkt anzusprechen und es bequemer zu machen, um vom strengen Modus zu profitieren, sind sie dem ausgewichen und haben C # ?. nachgeahmt, um einen hinterhältigen Ausweg aus der von Ihnen gewünschten Strenge zu finden, was leicht praktisch ist für dich, aber scheiße für alle anderen. Und du hast immer noch keinen Existenz-Test für Mitglieder, und vom Strictmode zu profitieren ist immer noch wortreich und lästig, aber zumindest musst du das nicht leiden, weil 'Strictmode' eine 'Normalmode'-Notluke hat jetzt". Ick.

Wenn ich strengen Code geschrieben habe, der bei der Verwendung fehlschlägt, hat einer von uns einen Fehler gemacht.

Obwohl ich nicht verstehe, warum Sie denken, dass eine einfache Nullprüfung bei der Suche nach Mitgliedern eine schlechte Sache wäre, ist die tatsächliche Suche nach Mitgliedern viel teurer als wenn (Ergebnis ist null)

Ich denke nicht, dass das schlecht wäre, PS non-strictmode macht das bereits, und ich denke, das wäre eine wünschenswerte Alternative zu den vorgeschlagenen ?. - sehr unterschiedlich, nützlich in mehr Situationen.

Beachten Sie jedoch, dass Sie in PS etwas tun können, was C # nicht kann:

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

und keine Ausnahmen im nicht strengen Modus. Ändern Sie die Zahlen und sehen Sie, wie lange es dauert; Gemessen an der Leistung und wie ich denke, dass es hinter den Kulissen funktionieren muss, um in beliebige Objekte zu indizieren, scheint es tatsächlich ~ 100.000 Ausnahmen zu geben, die für unsere Bequemlichkeit ausgelöst und zum Schweigen gebracht werden. PS trifft nicht immer die Wahl "Muss so schnell wie möglich sein, die Unannehmlichkeiten auf den Benutzer übertragen", und das gefällt mir daran.

@HumanEquivalentUnit Es gibt viele Funktionen in jeder Sprache, die Sie möglicherweise nie in Ihrer Karriere verwenden. Wenn Ihnen der Stil nicht gefällt, ist das in Ordnung, Sie müssen diese Funktionen nicht verwenden. Ich verstehe nicht, warum Sie den strengen Modus abschreiben. Es ist eine gute Praxis in Skripten, sich bewusst mit Problemen zu befassen, anstatt sie von der Sprache verschlucken zu lassen (und im Wesentlichen überall leere Fangblöcke zu haben). Auch hier können Sie die Funktionen gerne nicht verwenden (z. B. habe ich noch nie Out-Default ).

Außerdem ist der Operator ? , nicht ?. ; es würde auch mit Indexzugriff funktionieren.

Um weiterhin die Grundlage für weitere Diskussionen zu schaffen, möchte ich zusammenfassen, wie sich die bestehenden strengen Modi auf den Zugriff mit Nullwertbedingungen und auf die Existenz von Mitgliedern auswirken (die oben eingeführten Begriffe):

Die folgenden Spalten stellen die Set-StrictMode -Einstellungen dar, und die Spaltenwerte geben Folgendes an:

  • 👍 ... erlaubt
  • 🚫 ... verboten (verursacht einen Fehler beim Beenden der Anweisung)

Nebenbei bemerkt: Die Tatsache, dass die Fehler nur _statement-_ und nicht _script_-terminierend sind, bezieht sich auf die größere Diskussion um die Fehlerbehandlung von PowerShell - siehe https://github.com/PowerShell/PowerShell-Docs/issues/1583.

  • _Null-value_-bedingter Zugriff - $obj _itself_ ist $null :

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

Es ist merkwürdig, dass mit -Off und -Version 1 $obj.Prop erlaubt ist, während $obj[42] nicht erlaubt ist.

  • _Mitglied-Existenz-bedingter Zugriff - $obj ist nicht $null , aber das Mitglied / Element, auf das zugegriffen wird, existiert nicht:

Konstruieren | -Aus | -Version 1 | -Version 2 | -Version 3+
---------- | ---- | ---------- | ---------- | ------------
$ obj.Prop | 👍 | 👍 | 🚫 | 🚫
$ obj [42] (indexierbar) | 👍 | 👍 | 👍 | 🚫
$ obj [42] (nicht indizierbar) | 👍 | 👍 | 🚫 | 🚫
$ obj.Method () | 🚫 | 🚫 | 🚫 | 🚫

Es ist merkwürdig, dass inhärent indizierbare Objekte (z. B. Arrays) den Zugriff auf nicht vorhandene Elemente auch mit -Version 2 , während Skalare, bei denen PowerShell Indizierungsfunktionen für eine einheitliche Behandlung mit Sammlungen bereitstellt, dies nicht tun.

Der Null-Soaking-Operator ( null-bedingt oder Elvis in C # ) ist fast obligatorisch, wenn Sie in StrictMode Latest ausgeführt werden und versuchen, auf eine Eigenschaft zuzugreifen, die möglicherweise vorhanden ist oder nicht. Derzeit muss man auf solche dummen Tricks zurückgreifen:

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

wenn Sie wirklich nur schreiben können sollten:

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

Bitte Leute, wenn Sie diesen Vorschlag nur null-bedingt und nur für Immobilien umsetzen könnten, würde dies so vielen Menschen so viel Schmerz ersparen.

Ich fing an, mir das anzuschauen und fand ein paar Probleme.

Betrachten wir ?? und ?=

$x ?= 1 und $x ?? 1 scheinen unkompliziert zu sein. Da es sich jedoch um Betreiber handelt, müssen wir $x?=1 und $x??1 .

Das Problem dabei ist, dass $x? und $x?? beide Variablennamen in PowerShell validieren. Die einzige Möglichkeit zur Disambiguierung wäre ${x}?=1 und ${x}??1 .

Und darüber hinaus müssten wir für den bedingten Mitgliederzugriff ?. und ?[] ${x}?.name und ${x}?[0] .
Für diese werden $x ?.name und $x ?[0] nicht unterstützt.

Die andere Option besteht darin, eine wichtige Änderung einzuführen und ? im Variablennamen überhaupt nicht zuzulassen.

Was denken Sie? @ mklement0

/ cc @rjmholt @ daxian-dbw @JamesWTruher

Ich habe nie besonders gemocht oder verstanden, warum ? ein gültiger Variablenname ist. Es öffnet die Tür für Namen wie $Safe? was im Allgemeinen klarer und weniger umständlich ist, wenn es sowieso als $IsSafe wird.

Ich denke, dass die Veränderung wahrscheinlich lange auf sich warten lässt.

Es öffnet die Tür für Namen wie $ Safe? Das ist im Allgemeinen klarer und weniger umständlich, wenn es sowieso als $ IsSafe geschrieben wird

Interessanterweise drückte ich das gegenteilige Gefühl aus. Es ist eine klassische Scheme / Ruby- Tradition.

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

Hatte der ternäre Operator nicht das gleiche Problem, bei dem für die Auflösung Leerzeichen um den Operator oder geschweifte Klammern um den Variablennamen erforderlich waren, damit er ordnungsgemäß mit Variablen funktioniert, die mit ? enden?

Ich würde erwarten, dass PowerShell mit der Einführung dieser Operatoren das Erkennen von ? als Teil des Operators in Syntax wie $x?[0] priorisiert, sodass Benutzer, die Variablennamen verwenden, die auf ? enden ${x?}?[0] . Das Gleiche gilt für $x?.Name und ${x?}?.Name .

Die andere Option ist, eine brechende Änderung einzuführen und nicht zuzulassen? im Variablennamen überhaupt.

👍 Angesichts der Tatsache, dass es sich um eine wichtige Versionsänderung handelt (6 bis 7), halte ich es hier für eine wichtige Änderung. Ich wünschte, GitHub hätte eine bessere Codesuche, um zu sehen, wie viele Instanzen von PS-Variablen mit einem ? enden. Ich vermute, dass dies nicht so wirkungsvoll wäre, aber es wäre schön, dies gegen GitHub zu überprüfen. In 14 Jahren mit PowerShell habe ich noch nie ein ? in einem Variablennamen verwendet, aber vielleicht bin das nur ich. :-)

Dieses Schiff ist schon vor langer Zeit gesegelt, und ich wäre nicht überrascht zu sehen, dass Variablen, die heute mit ? enden, in Skripten verwendet werden.

Wenn wir bei diesen neuen Operatoren lediglich das Parsen von ? als Teil eines Operators und nicht als Teil eines Variablennamens priorisieren, benötigen Leute, die Variablennamen verwenden, die auf ? enden Verwenden von {} oder Leerzeichen (wobei Leerzeichen zulässig sind), um diese Variablen mit diesen Operatoren zu verwenden.

Es ist seltsam, in diesem Zusammenhang den Satz "das Schiff ist gesegelt" zu hören. Dies ist eine wichtige Versionsänderung. Es ist nicht unangemessen, dass sich dies hier ändert, denke ich.

@rkeithhill Ich habe es in persönlichen

@KirkMunro mit "priorisiertem Parsen" klingt wie eine offene Tür für Fehler.

@ vexx32 : Es ist nicht unangemessen, eine Änderung ? enden, solange sie {} Gehäuse zur Identifizierung des Variablennamens.

Beachten Sie, dass Sie einen Eigenschaftsnamen haben können, der ebenfalls mit ? endet. Wenn Sie derzeit versuchen, eine solche Eigenschaft in PowerShell anzuzeigen, ohne den Namen in Anführungszeichen zu setzen, wird ein Parserfehler angezeigt.

Zum Beispiel:

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

Ich bin ein wenig überrascht, dass heute nicht analysiert wird (warum wird das nicht analysiert?), Aber unabhängig davon müssen Sie für solche Eigenschaften ihren Namen in Anführungszeichen setzen. In diesem Fall können Sie dem Anführungszeichen eine ternäre Null folgen -koalescing, etc. Operator ohne Leerzeichen und es würde gut funktionieren. Ich finde diese Syntax sehr ähnlich zu ${x?}?.name , und ich bin mit der Haltung einverstanden, dass Sie solche Variablen- / Eigenschaftsnamen verwenden können, wenn Sie möchten, aber solche Namen erfordern möglicherweise zusätzliche Syntax oder Abstände, um mit ternär oder null zu arbeiten - * Operatoren.

@KirkMunro Nichts künftig Variablengrenzen zu verwenden, wenn sie esoterische Variablennamen möchten. Ich stimme den anderen darin zu, dass ich mich frage, wie die aktuelle Verwendung dieses Verhaltens derzeit verwendet wird.

Die Benutzer von PowerShell 7 sind wahrscheinlich bereits Enthusiasten und werden sich der bahnbrechenden Änderungen bewusst sein. Personen, die dies nicht tun, verwenden immer noch <= v5.1 und werden dies noch lange tun. wahrscheinlich bis msft es von Windows 10 entfernt (nie).

@KirkMunro Sicher, aber das Entfernen aus den zulässigen Standardvariablenzeichen hindert Benutzer nicht daran, nur ${Valid?} als Variablennamen zu verwenden. Da sie dies mit diesen Operatoren unabhängig davon tun müssten, wäre es meiner Meinung nach besser, sie nur konsistent zu machen, als ? zu einem Zeichen zu machen, das _nur manchmal_ als Teil eines Variablennamens betrachtet wird.

Das wird schon eine bahnbrechende Veränderung sein, und ich würde es für das Beste halten, zumindest konsequent zu sein und den ganzen Weg zu gehen, anstatt eine andere Ebene der Mehrdeutigkeit einzuführen. 🙂

@adityapatwardhan Ich denke, es wäre besser für die Sprache, ? als gültiges Variablenzeichen zu entfernen. Es würde leicht sowohl Null-Soak / Coalesce- als auch ternäre Operatoren in einer vertrauten Syntax aktivieren, die dem Skript-Erstellungsprozess viel Ergonomie verleiht.

@KirkMunro mit "priorisiertem Parsen" klingt wie eine offene Tür für Fehler.

@ TheIncorrigible1 : Jeder Code kann die Tür für Fehler öffnen, wenn er nicht richtig implementiert ist. Ich spreche nur von einem einfachen Einzelzeichen-Lookahead, um festzustellen, ob PowerShell auf einen ternären oder Null- * -Operator stößt, wenn ein Variablenname analysiert wird, der nicht in Variablengrenzen eingeschlossen ist und auf ein ? -Zeichen stößt. Das ist nicht kompliziert und öffnet nicht die Tür für mehr Fehler als jede andere Codeänderung.

Die Benutzer von PowerShell 7 sind wahrscheinlich bereits Enthusiasten und werden sich der bahnbrechenden Änderungen bewusst sein. Personen, die dies nicht tun, verwenden immer noch <= v5.1 und werden dies noch lange tun. wahrscheinlich bis msft es von Windows 10 entfernt (nie).

@ TheIncorrigible1 : Welche Grundlage / Beweise haben Sie für diese Aussage? PowerShell 7 befindet sich in der Vorschau und wird heute nur noch von Enthusiasten verwendet. Das ist eine gegebene. Wenn PowerShell 7 oder höher jedoch über die Vorschau hinaus überzeugende Funktionen bietet, die Unternehmen benötigen, und gleichzeitig die von ihnen benötigten Funktionen unterstützt, werden diese Versionen verwendet. Dies gilt insbesondere dann, wenn PowerShell 7 mit dem Betriebssystem installiert wird. Der einzige Punkt, den Enthusiasten ins Spiel bringen, sind Unternehmen, die keine geschäftlichen Anforderungen an das haben, was PowerShell 7 auf den Tisch bringt.

Das wird bereits eine bahnbrechende Veränderung sein, und ich würde es für das Beste halten, zumindest konsequent zu sein und den ganzen Weg zu gehen, anstatt eine andere Ebene der Mehrdeutigkeit einzuführen. 🙂

@ vexx32 Das streckt es. Es wäre eine bahnbrechende Änderung, wenn Sie ?? in einem Variablennamen hätten, aber die Wahrscheinlichkeit dafür ist viel geringer als bei einer Variablen, deren Name auf einem einzelnen ? endet. Abgesehen davon, wie würde die Einführung von Null- * -Operatoren bei gleichzeitiger Unterstützung von ? als standardmäßige zulässige Skripts zur Unterbrechung von Variablenzeichen heute funktionieren?

Nach meiner Erfahrung werden bahnbrechende Änderungen für nette Leute (was dies zu sein scheint) bei weitem nicht abgelehnt, und die Diskussion / Argumente um sie herum dienen nur dazu, den Prozess der dramatischen Erledigung von Dingen zu verlangsamen Der Punkt, an dem die Dinge einfach stehen bleiben oder nicht in eine Veröffentlichung aufgenommen werden usw. Die Verlangsamung ist oft notwendig, denn wenn Sie eine brechende Änderung vorschlagen, sind Beweise erforderlich, um die Auswirkungen beurteilen und eine solche Änderung rechtfertigen zu können. Es ist heute schwer, diese Beweise zu sammeln. Ich sage das nur, weil ich mich dafür entscheide, jetzt Funktionen zu erledigen, anstatt jeden Tag über eine schöne Änderung zu streiten.

Ich verwende niemals ? in Variablennamen und ich auch nicht. Ich erwarte jedoch, dass einige Leute dies tun, da es in einem Skript sehr gut lesbar ist und unnötige Eintrittsbarrieren für PowerShell 7 nur die Akzeptanz verlangsamen. Besonders wenn viele Leute, die mit PowerShell arbeiten, keine Entwickler sind, die eher daran gewöhnt sind, Änderungen zu bearbeiten.

Jedenfalls ist es nicht meine Absicht, diesen Prozess zu verlangsamen - eher das Gegenteil. Aber ich habe meine Gedanken und Erfahrungen geteilt, daher werde ich nicht weiter darauf eingehen, ob wir hier auf eine bahnbrechende Veränderung drängen sollten oder nicht.

Betrachten Sie dieses erfundene Beispiel:

$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.

Dieses Verhalten würde bereits mit den vorgeschlagenen Änderungen brechen. Ich würde eine konsistente, saubere Pause einer verwirrenden Pause vorziehen, die eine halbseitige Erklärung benötigt, um alle möglichen Ausnahmen aufzulisten und wann und wo ? plötzlich nicht mehr gültig ist und wo sie noch ist.

@KirkMunro Wenn PowerShell 7 oder höher überzeugende Funktionen bietet, die Unternehmen benötigen, und die von ihnen benötigten Funktionen unterstützt, werden sie diese Versionen verwenden. Dies gilt insbesondere dann, wenn PowerShell 7 mit dem Betriebssystem installiert wird.

Nachdem ich in einigen Fortune 50-Jahren mit einigen Hunderttausenden von Mitarbeitern gearbeitet hatte, war es eine Herausforderung, von den Standardeinstellungen des Betriebssystems abzuweichen (dh auf v5.x umzusteigen). Ich habe noch keinen Ort gesehen, an dem Core übernommen wurde . Aus Gründen der Kreuzkompatibilität wechseln sie lieber zu Python. Das Aktivieren der optionalen Windows-Funktionen war ebenfalls eine ziemlich seltene Aufgabe.

Ich denke, Unternehmen arbeiten mit dem, was sie haben, und der Wissensbasis ihrer Mitarbeiter, um nach neuen Technologien oder Sprachversionen zu suchen, um ihre Probleme zu lösen. Einige wären vollkommen zufrieden damit, für immer auf v2 zu bleiben und niemals die Win10 / Server16-Cmdlets zu berühren, die das Leben dramatisch erleichtern.

Mein Punkt bei all dem ist, dass diese Funktionen nicht im luftleeren Raum sind. Wenn Sie eine Sprache ergonomischer gestalten, werden die an dem Tool interessierten Personen eine größere Akzeptanz finden, um die Probleme, die sie haben, schneller zu lösen. (Siehe: C # und die zunehmende Beliebtheit mit mehr / besseren Sprachfunktionen)

In Bezug auf Variablen, die mit ? enden - könnte dies aufgrund der automatischen Variablen $? .

@lzybkr Ich vermute, der beste Fall, um damit umzugehen, ist ein Sonderfall, wie er bereits für $^ und $$ .

@lzybkr @ TheIncorrigible1 Soweit ich mich erinnere, sind alle diese Variablen im Tokenizer explizit in speziellen Fällen enthalten. $^ _already_ ist kein gültiger Variablenname. Der Tokenizer hat Sonderfälle für alle, bevor er nach Standardvariablennamen sucht.

Die einzige Lösung besteht darin, ¿ :

$ dumm? ¿= 1

Ich weiß nicht, Steve, ich bin fest in der Interrobang-Menge.

$silly?‽=1

@lzybkr - Meines Wissens werden $? $$ und $^ auf besondere Weise behandelt.

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

Zusammenfassend haben wir diese vier Optionen

  • Große bahnbrechende Änderung - erlauben Sie nicht ? in den Variablennamen.
  • Bevorzugen Sie ?. als Operator. Dies bedeutet, dass Variablennamen, die mit ? enden, die Syntax ${variablename} . Immer noch eine bahnbrechende Veränderung.
  • Bevorzugen Sie altes Verhalten. Dies bedeutet, dass für die Verwendung von ?. und ?[] ${variablename}?.property verwendet werden muss. Keine bahnbrechende Änderung, macht aber die Verwendung der neuen Operatoren ungeschickt.
  • Implementieren Sie die neuen Operatoren nicht.

Ich persönlich bevorzuge nicht den 1. und den letzten.

Dies ist eine wichtige Versionsänderung. Es ist nicht unangemessen, dass sich dies hier ändert, denke ich.

Ich denke, ein wichtiger Punkt ist, dass die Hauptversion erhöht wird, um die Bereitschaft zum Ersetzen von Windows PowerShell zu signalisieren, was bedeutet, dass dies auf Kompatibilität und nicht auf Bruch hinweist. Aus der ursprünglichen Ankündigung :

Beachten Sie, dass die Hauptversion nicht bedeutet, dass wir wesentliche Änderungen vornehmen werden.

Sind die Optionen 1 und 2 nicht gleich? Oder dürfen Variablen weiterhin ? falls ihnen kein nullkoaleszierender oder ternärer Operator folgt?

Wenn ja, haben wir möglicherweise große Probleme, die Tokenisierungs- / Parsing-Logik ohne viel Backtracking zu handhaben. Dies kann zu Leistungseinbußen führen, wenn Variablen mit ? enden.

Angesichts dessen, was ich sehen kann, scheint Option 2 die allgemeine Präferenz zu sein, und ich bin mir nicht sicher, ob ich die Zurückhaltung verstehe, die bahnbrechende Änderung hier vorzunehmen. Auf diese Weise wird die Verwendung von ? in Variablennamen ohnehin aktiv unterbunden, indem einfach Szenarien eingeführt werden, die ohne den Variablennamen nicht verwendbar sind.

Ich denke, dies ist eine ziemlich geringfügige Änderung, wenn es darum geht, Änderungen zu ändern, und meiner Meinung nach ist es wahrscheinlich die schlechtere Option, die Konsistenz dessen zu unterbrechen, was in einem Variablennamen verwendet werden kann und was nicht.

Diese Dinge sollten klare Regeln haben, die in so ziemlich allen Situationen gelten. Derzeit ist dies der Fall. Wir schlagen vor, das Wasser hier zu trüben und das Verhalten _less_ klar zu machen. Ich kann nichts Gutes daraus sehen, außer vielleicht, dass Variablennamen, die ? , weniger verwendet werden, nur weil sie in einigen Szenarien schwieriger zu verwenden sind - was uns (effektiv) direkt zu Option 1 zurückbringt Standardmäßig fast ... also sehe ich keinen besonderen Grund, jetzt keine Pause einzulegen und nur das mehrdeutige Verhalten zu vermeiden.

@ vexx32 Es gibt einen kleinen Unterschied zwischen 1 und 2.

Für # 1 verbieten wir, dass ? in Variablennamen verwendet wird. Dies bedeutet, dass $x? = 1 , $x?? = 1 $x?x?x = 1 nicht analysiert werden.

Für # 2 ist $x? = 1 noch gültig, aber $x?.name entspricht ${x}?.name . Dies bricht nur Variablennamen mit ? am Ende, die auf Mitglieder zugreifen. Also, $x? = 1 , $x?? = 1 $x?x?x = 1 wäre immer noch gültig.

Ja, ich wäre ein wenig besorgt darüber, den Overhead dort zu tokenisieren. Es könnte sich lohnen, beide Möglichkeiten zu implementieren und einige Benchmarks für ein Skript durchzuführen, das ähnliche Variablennamen relativ häufig verwendet.

Meine Präferenz ist definitiv Option 1 ... eine einmalige bahnbrechende Änderung ist für mich zumindest viel besser, als sich mit den Inkonsistenzen befassen zu müssen, wie dies bis in die Zukunft analysiert werden kann.

Wenn ja, haben wir möglicherweise große Probleme, die Tokenisierungs- / Parsing-Logik ohne viel Backtracking zu handhaben. Dies kann zu Leistungseinbußen führen, wenn Variablen mit? Beenden.

Ich teile diese Besorgnis über diese Möglichkeit. ? als manchmal-Token-Trennzeichen zu haben, fühlt sich für mich wie eine gezackte Linie in der Sprache an.

Wenn ja, haben wir möglicherweise große Probleme, die Tokenisierungs- / Parsing-Logik ohne viel Backtracking zu handhaben. Dies kann zu Leistungseinbußen führen, wenn Variablen mit? Beenden.

Es hängt davon ab, wie Sie es implementieren. Solange Sie eher einen Lookahead-Ansatz als einen Tokenize- und dann einen Backup-Ansatz wählen, sollte es Ihnen gut gehen. Sie können vorausschauen, welche Zeichen als Nächstes kommen, wenn Sie in einem Variablennamen auf ein ? stoßen, und eine Entscheidung darüber treffen, wie Sie das Variablentoken basierend auf den nächsten Zeichen "einpacken" möchten. Das ist kein großes Problem und sollte kein Backtracking erfordern oder zu spürbaren Leistungseinbußen führen.

@ PowerShell / Powershell-Komitee hat dies heute überprüft, wir haben ein paar Gedanken:

  • Egal, was wir tun, wir werden einige Analysen unseres Skriptkorpus durchführen, um festzustellen, wie oft Leute ? in Variablennamen verwenden
  • Einige von uns haben die Hypothese (die andere gerne validieren würden), dass die Benutzer, die ? in ihren Variablennamen verwenden, möglicherweise weniger fortgeschrittene Benutzer sind (da wir uns in diesem Raum einig sind, würden wir uns davon fernhalten, weil der möglichen Probleme, die auftreten könnten). Auf der anderen Seite kann jeder, der die hier beschriebene Funktionalität verwendet, eine etwas kompliziertere Syntax verstehen (wie ${foo}?.bar ). Daher bevorzugen wir Option 3, da dadurch Änderungen an diesen weniger erfahrenen Benutzern vermieden werden. (Aber wir werden es erneut anhand der ersten Kugel validieren.)
  • @ daxian-dbw hat einen guten Punkt angesprochen, der es schwieriger macht, alle variablen Referenzen zu finden, wenn Skripter die Verwendung von $foo und ${foo} mischen. Wir waren uns jedoch einig, dass dies in Tools (wie der VS Code PowerShell-Erweiterung) behoben werden kann und Benutzer wie Suchsyntax übereinstimmen können.

Es ist schwieriger, alle variablen Referenzen zu finden, wenn Scripter die Verwendung von $ foo und $ {foo} mischen.

Dies hängt davon ab, ob der AST den Variablennamen danach unterscheidet, ob er die geschweiften Klammern gesehen hat. Ich vermute, dass jedes Tool, das PowerShell AST verwendet, hier keine Probleme mit geschweiften Klammern hat.

Aber für Regex bedeutet dies sicherlich, dass Sie sich mehr bewusst sein müssen: varname -> \{?varname\}?

@rjmholt Ich habe eine Analyse über hier . Eine kurze Aufschlüsselung: Von fast 400.000 Skripten mit mehr als 22.000.000 Variablennamen (nicht eindeutig) gab es nur ~ 70 eindeutige Variablen, die mit ? endeten.

Danke, @mburszley - mir , dass es eine macht Bucket 3: Es ist {...} $(...) unwahrscheinlich Grauzone ändern und belastende Benutzer mit der Notwendigkeit für {...} ist sehr bedauerlich, Parallelisierung die unglückliche Notwendigkeit für $(...) um exit / return / throw Anweisungen im Kontext von && und || .

Um die Argumentation aus diesem Problem auszuleihen:

Wenn wir die Verwendung von {...} um Variablennamen erzwingen, nur damit Sie ?. :

  • Neue Benutzer erwarten nicht die Notwendigkeit von {...} und wissen nicht unbedingt, dass _it_ erforderlich ist, wenn Folgendes fehlschlägt (möglicherweise _undetected_, es sei denn, Set-StrictMode -Version 2 oder höher ist in Kraft): $o = [pscustomobject] @{ one = 1 }; $o?.one

  • Selbst wenn Benutzer _do_ über die Notwendigkeit von {...} Bescheid wissen:

    • Sie werden vergessen, es gelegentlich zu benutzen, weil es nicht intuitiv benötigt wird.
    • Wenn sie sich erinnern, wird diese scheinbar künstliche Anforderung eine ständige Quelle der Frustration sein, zumal {...} schwer zu tippen ist.

Dieses Problem wurde als behoben markiert und hatte 1 Tag lang keine Aktivität. Es wurde aus Reinigungsgründen geschlossen.

@rjmholt , zitiert Sie aus https://github.com/PowerShell/PowerShell/issues/10967#issuecomment -561843650:

Die Art und Weise, wie wir die vorhandene gültige Syntax analysieren, nicht zu brechen, war der richtige Weg. Auch hier ist eine Änderung nicht nur ein Fall, in dem wir die Entscheidung treffen, eine kleine Anzahl wilder Programme zu unterstützen. Wir haben zahlreiche bahnbrechende Änderungen vorgenommen, wenn wir der Meinung waren, dass die Vorteile die Nachteile überwiegen (nicht, dass ich persönlich zustimme mit allen von ihnen, oder dass diese andere rechtfertigen oder nicht). Das Problem ist, dass das Ändern eines Aspekts des Tokenizers oder Parsers dazu führt, dass zwei PowerShell-Versionen für einige Skripte nicht mehr denselben AST generieren, sodass zwei PowerShells dasselbe Skript unterschiedlich "sehen". Das bedeutet, dass wir die Syntax nicht einmal auf die gleiche Weise lesen können. Es gibt also keine PSScriptAnalyzer-Regel, die Sie schreiben können, um mögliche Probleme zu erkennen. PSScriptAnalyzer sieht eine andere Syntax von einer PowerShell-Version zur nächsten.

Im Gegensatz zu C # kann PowerShell keine andere Syntax als ein kompatibles Format für die spätere Ausführung vorkompilieren. Dies bedeutet, dass eine syntaktische Änderung an die Laufzeit gebunden ist. Sobald PowerShell eine syntaktische Unterbrechung durchführt, reduzieren wir die Anzahl der Skripts, die für verschiedene Versionen verwendet werden können. Dies bedeutet, dass Benutzer gezwungen sind, zwei Skripts zu schreiben. Dies ist ein ernstes Problem für eine Shell und eine Skriptsprache. PowerShell soll dynamisch genug sein, um alle logischen Unterschiede in einem Skript zu überwinden, aber die Syntax ist die einzige nicht verhandelbare statische Sache, die wir haben. Und eine Syntaxänderung vorzunehmen, bei der sowohl vorher als auch nachher gültig ist, ist besonders schädlich, da es keine einfache Möglichkeit gibt, sie zu erkennen, keine Warnung dafür gibt und Benutzer selbst nach der Ausführung in beiden Umgebungen möglicherweise nicht wissen, dass ein anderes Verhalten aufgetreten ist.

Im Allgemeinen kann ich verstehen, dass solche Änderungen sehr problematisch sein können und nur vorgenommen werden sollten, wenn die Vorteile die Nachteile überwiegen. Ein wichtiger Faktor dafür ist, wie viel vorhandener Code bricht.

Wir reduzieren die Anzahl der Skripte, die gegen verschiedene Versionen arbeiten können
Dies bedeutet, dass Benutzer gezwungen sind, zwei Skripte zu schreiben

Wir sprechen hier von einer neuen syntaktischen Funktion ( ?. ), sodass per Definition Skripte, die sie verwenden, nicht (sinnvoll) auf älteren Versionen ausgeführt werden können - es sei denn, Sie fügen ausdrücklich Bedingungen hinzu, die mit Legacy-Versionen kompatible Codepfade bereitstellen. aber das scheint sich kaum zu lohnen - man würde sich dann einfach an die alten Funktionen halten.

Ja, die Interpretation von $var?.foo in alten Skripten, in denen $var? als Variablenname verwendet wurde, würde nicht funktionieren, aber:

  • ? hätte niemals als Teil eines Bezeichners zugelassen werden dürfen, ohne ihn in {...} _ einzuschließen.

  • Da dies unerwartet und für viele wahrscheinlich sogar unbekannt ist, sind solche Variablennamen in freier Wildbahn aus persönlicher Erfahrung äußerst selten, aber die Analyse von @mburszley liefert greifbarere Beweise .

    • Sogar Ruby erlaubt nur ? (und ! ) am Ende von Bezeichnern und dort nur von Methodenbezeichnern, und ich vermute, dass die meisten Ruby-Benutzer wissen, dass sie nicht davon ausgehen sollten, dass andere Sprachen unterstützen das gleiche.

Also pragmatisch gesehen:

  • Die überwiegende Mehrheit des vorhandenen Codes ist nicht betroffen - ein Token wie $var?.foo wird einfach nicht angetroffen.

  • Wenn Sie $var?.foo mit der neuen Semantik schreiben, kann das Ausführen dieser Version in älteren Versionen zu einem anderen Verhalten führen (anstatt auf offensichtliche Weise zu brechen), je nachdem, welcher strenge Modus wirksam ist - aber Sie sollten es immer tun Erzwingen Sie die Mindestversion, die erforderlich ist, um Ihren Code wie beabsichtigt auszuführen ( #requires -Version , Modulmanifestschlüssel).

Alles in allem ist dies für mich ein klarer Fall einer Änderung von Bucket 3: eine technisch nicht funktionierende Änderung, die nur sehr wenig vorhandenen Code zerstört und gleichzeitig echte Vorteile bietet (oder umgekehrt mehrjährige Kopfschmerzen aufgrund unerwarteten Verhaltens vermeidet).

@ mklement0 Wir halten den nullbedingten Zugriff für PS7.0 experimentell. Vielleicht können Sie eine neue Ausgabe eröffnen, um diese Diskussion für 7.1 fortzusetzen?

Hört sich gut an, @ SteveL-MSFT - siehe # 11379.

Ich ermutige alle hier, dort wieder Unterstützung zu zeigen (oder nach Luft zu schnappen, nicht zu unterstützen).

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen