Powershell: Sugerencia: implementar acceso nulo-coalescente, nulo-condicional (nulo-remojo), asignación nulo-condicional

Creado en 2 mar. 2017  ·  71Comentarios  ·  Fuente: PowerShell/PowerShell

El acceso nulo-coalescente y nulo-conditonal (remojo nulo) serían adiciones útiles al lenguaje.

_Update_: @BrucePay también sugiere una _asignación_ condicional nula , con ?= - vea el comentario a continuación .

Por ejemplo, en lugar de escribir:

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

uno podría escribir:

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

Re acceso condicional nulo: con Set-StrictMode desactivado (el valor predeterminado), puede usar $varThatMayBeNull.Name - no se necesita una sintaxis especial; sin embargo, si Set-StrictMode -Version 2 o más está en efecto, $varThatMayBeNull.Name _break_ y ahí es donde el operador condicional nulo ( ?. ) es útil, para señalar la intención explícita de ignorar el $null de manera concisa.


Pregunta abierta :

$varThatMayBeNull?[42] maneja el caso donde la variable es $null , pero si no lo es, debe existir un elemento de matriz con el índice especificado _debe existir_.

Por lo tanto, también sería útil hacer que _indexing_ sea nulo-condicional , algo que C # no admite _no_, por cierto (debe usar .ElementAtOrDefault() ).

Las dos opciones básicas son:

  • Piense en una sintaxis adicional que indique explícitamente la intención de ignorar un _index_ inexistente:

    • La pregunta es qué sintaxis elegir para esto, dado que ?[...] y [...]? no son una opción debido a la ambigüedad.
    • Quizás [...?] , pero eso parece incómodo.
  • Confíe en el comportamiento existente con respecto al acceso a índices inexistentes, como lo implica la configuración Set-StrictMode ; consulte la tabla a continuación .


Relacionado: implementar condicionales ternarios

Issue-Enhancement Resolution-Fixed WG-Language

Comentario más útil

@rjmholt Hice un análisis aquí . Un desglose rápido: de casi 400,000 scripts con más de 22,000,000 de nombres de variables (no únicos), solo había ~ 70 variables únicas que terminaban en ? .

Todos 71 comentarios

@ mklement0 Parece que la segunda muestra funciona por diseño sin "?".
¿Quizás cambiar a name() ?

@iSazonov : Buen punto, pero solo funciona sin ? menos que Set-StrictMode -Version 2 o superior _no_ esté en vigor. He actualizado la publicación inicial para dejarlo en claro.

Creo que el azúcar sintáctico es algo que PowerShell podría usar y que otros lenguajes disfrutan. +1 en la propuesta.

Considere los siguientes ejemplos de otros idiomas:

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

incluso

a = b if b else c

es mejor que

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

y muchas veces necesita aclarar con el adicionalmente detallado

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

Hace que uno se sienta sucio y golpeado.

Me encontré haciendo esto hoy como una solución.

`` powershell
$ palabra = ($ nulo, "dos", "tres"). Donde ({$ _ -ne $ nulo}, "Primero")
`` ``

Yo uso un patrón similar:

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

@kfsone Hay un pequeño error en su ejemplo $a=(if ($b -ne $null) { $b } else { $c }) . Debería ser $a=$(if ($b -ne $null) { $b } else { $c }) sin embargo, la única versión de PowerShell donde se requería $( ) era la versión 1. A partir de la v2, simplemente puede hacer:

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

@bgshacklett ¿No te refieres a $word=($null,'two')[$null -ne 'three'] ?

Es un poco desafortunado que haya pasado de 6.1 a 6.2 a "Futuro".

@ TheIncorrigible1 No, si copia y pega lo que agregué arriba, debería ver que el valor de $word se establece en "dos". Hay más detalles en esta respuesta de Stack Overflow donde vi el patrón por primera vez:
https://stackoverflow.com/a/17647824/180813

Si bien los hack-around perlescos atraen al yo de hace 20 años que escribí un shebang que registró y / o consultó a un usuario de RIPE-DB u registro de organización, lo que espero de PowerShell es algo que anime a mis colegas a usar el lenguaje. en lugar de infundirles miedo.

Mi prueba de fuego es esta: ¿Me gustaría leer esto a través de mi tableta a las 3 a.m. de la mañana de Año Nuevo con resaca y el director ejecutivo al teléfono me llora cuántos millones de dólares estamos perdiendo por segundo?

(Aparte: esto fue solo una exageración vaga de una experiencia real hasta que trabajé en Facebook y regresé de una filtración rápida y urgente para que me dijeran que, en los 2 minutos que me fui, más personas que la población de Holanda se habían quedado sin feed de noticias. No era mi código y el error fue un cambio de minuto en la semántica de return x vs return (x) en el estándar c ++ para casos de plantilla muy específicos, y "¿le gustaría leer este código con 2 minutos fecha límite, vejiga llena y el destino de todos los zuecos con imágenes de gatos holandeses en tu hombro? "no sonaba tan genial)

Sip. Hay algunos trucos ingeniosos posibles en PS que son excelentes en caso de apuro o si necesita una taquigrafía de una sola vez.

Para un código mantenible, idealmente deberíamos tener operadores de fusión nulos explícitos como C #. El principal problema para mí es: ¿qué usamos para esos? ? ya tiene un alias de Where-Object (por mucho que me encantaría que se borrara, es de uso muy común). Eso sí, % tiene un alias de ForEach-Object pero eso no obstaculiza las operaciones de módulo, por lo que en teoría al menos tener ? podría ser un operador de fusión nula multa; solo se interpretaría como tal en expresiones, donde Where-Object no es realmente válido de todos modos.

@ vexx32 :

Al menos _sintácticamente_ ?? debería estar bien, porque estamos hablando del modo _expresión_, mientras que ? , como comando [alias], solo se reconoce en el modo _argumento_.
No estoy seguro de si la reutilización del símbolo causa confusión, pero no sería la primera vez que un símbolo cumple una doble función en diferentes contextos.

Sorprendentemente, usar ?. y ?[] para remojo nulo sería técnicamente un cambio importante, porque PowerShell actualmente permite ? como carácter no inicial en un nombre de variable.

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

Sin embargo, espero que esto se considere un cambio del Cubo 3: Área gris poco probable .

¿No puedo decir que haya visto a alguien usar? en un nombre de variable ... Tampoco yo, porque es probable que se lea mal. Pero sí, espero que sea perfectamente utilizable.

Sospecho que es un poco tarde para mencionar esto, pero Bash ha manejado esto (y algunos otros casos) con sus funciones de sustitución de parámetros: https://www.tldp.org/LDP/abs/html/parameter-substitution.html.

Si bien puede ser difícil de aprender debido a la gran cantidad de cosas que se pueden hacer con él, es increíblemente poderoso. Entiendo que no sería posible usar esta notación exacta debido a la forma en que PowerShell usa llaves con variables, ni encajaría necesariamente con la sensación general del lenguaje, pero parece un punto de datos útil.

@bgshacklett :

Sí, la sustitución de parámetros es poderosa, pero, desafortunadamente, no solo es un oso _aprender_, sino también _recordar_.

Entonces, si bien las _características_ de Bash son a menudo interesantes, su _forma sintáctica_ suele ser arcana, difícil de recordar y no encaja bien con PowerShell.

_Brace expansion_ (por ejemplo, a{1,2,3} en bash expandiéndose a a1 a2 a3 ) es un ejemplo de una característica interesante cuya expresividad me encantaría ver en PowerShell, pero con PowerShell apropiado sintaxis - ver # 4286

Estoy completamente de acuerdo. Lo mencioné más como un ejemplo de cómo este problema se ha resuelto en otro lugar que como una solución exacta.

Hay otro operador a considerar posiblemente:

$x ?= 12

que establecería $x si no está establecido (no existe). Esto es parte del "patrón de inicialización" que no es común en los lenguajes convencionales, pero para los lenguajes (de ámbito dinámico) como shells, make tools, etc., es bastante común tener un script que establece un valor predeterminado si el usuario no lo ha especificado. . (Aunque, de hecho, los inicializadores de parámetros están bastante extendidos).

Extendiendo esto a las propiedades:

$obj.SomeProperty ?= 13

agregaría e inicializaría una propiedad de nota SomeProperty en el objeto si no existiera.

Y, por diversión, una variación más sobre la inicialización de una variable usando -or :

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

$x ?= 12 suena como una gran idea.

Se me ocurrió que probablemente deberíamos aplicar todos estos operadores no solo si el LHS no _existe_, sino también si _existe pero contiene_ $null (con [System.Management.Automation.Internal.AutomationNull]::Value tratados como $null en este contexto).

agregar e inicializar una propiedad de nota SomeProperty

En ese sentido, $obj.SomeProperty ?= 13 tiene sentido para mí _sólo_ si .SomeProperty existe y contiene $null , dado que no puede crear implícitamente propiedades incluso con asignaciones regulares (por el contrario, para _hasthables_ el la creación de entrada implícita tiene sentido).

Todos los operadores discutidos deberán eximir al LHS de la verificación de existencia en modo estricto.

Me pregunto cuál es la intención / razonamiento detrás de por qué el modo estricto le impide acceder a una propiedad que no existe. ¿La intención es detectar errores tipográficos como $x.pretnd ? ¿La intención es verificar suposiciones como assert(x != null) ? ¿La intención de bloquear la propagación accidental de $null más adelante en su código?

el empapado de nulos (?.) es útil para señalar la intención explícita de ignorar el $ null de manera concisa.

¿No es eso lo que . señala ya en modo no estricto? Si hubiera querido ser estricto, podría haber verificado .Name existentes primero, al no verificar primero, ya señaló la intención explícita de que verificar no era importante para usted.

Si StrictMode tiene un propósito en el que se prohíbe el acceso a una propiedad inexistente y devolver $null , entonces no se aplicará el mismo razonamiento a ?. , y eso debería generar la misma excepción por la misma razón . ¿Si no, porque no?

Con fusión nula, podría escribir:

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

¿Se volverá rápidamente recomendado o idiomático usar siempre ?. para cada referencia de propiedad, porque "se comporta como . y no arrojará excepciones para las personas que usan el modo estricto"?

Es el deseo real de tener un modo estricto configurable con ajustes variables, de modo que, por ejemplo, pueda tener una declaración en la parte superior de su script # StrictMode SkipMemberExistenceCheck , o un atributo de trama de escape para indicar un bloque de unstrict code ¿en general? [Sospecho que el deseo es una sintaxis concisa de estilo C #, pero sabes a qué me refiero]

Gracias por los pensamientos, @HumanEquivalentUnit.

¿La intención es detectar errores tipográficos como $x.pretnd ?

No puedo hablar sobre la intención del diseño, pero eso es lo que tiene sentido para mí, análogo a lo que Set-StrictMode -Version 1 hace para _variables_ (solo).

Con las variables se trata de su _existencia_, no de si el valor es $null , y la verificación de la existencia de la propiedad sigue el mismo patrón.

Pienso en ello como lo más cerca que puede llegar a estar un lenguaje de scripting dinámico para encontrar errores que un lenguaje compilado con tipado estático reportaría en _tiempo de compilación_.


No es eso lo que. señales ya en modo no estricto? Si hubiera querido ser estricto, podría haber verificado .Name existente primero

Sí, pero en el modo no estricto renuncia a las comprobaciones de existencia mencionadas anteriormente, y la prueba manual es obviamente bastante engorrosa, e invariablemente más lenta que una función incorporada.

al no verificar primero, ya indicó la intención explícita de que verificar no era importante para usted.

El punto es que, con Set-StrictMode -Version 2 o más, obtienes:

  • el beneficio de verificar la existencia de miembros _por defecto_
  • la opción de optar por no participar, _a pedido, de forma concisa_ con .?

podría tener una declaración en la parte superior de su secuencia # StrictMode SkipMemberExistenceCheck comandos unstrict code generalmente

Relacionado: El alcance dinámico actual de Set-StrictMode es problemático; consulte el borrador de RFC de @lzybkr para implementar un modo estricto _lexical_: https://github.com/PowerShell/PowerShell-RFC/blob/master/1-Draft/RFC0003-Lexical-Strict-Mode.md

el beneficio de la verificación de existencia de miembros por defecto

PS contiene código que verifica los miembros y devuelve $ null cuando no existen. Ese es un beneficio por defecto, que también puede evitar escribiendo su propia prueba de existencia de miembro con $x.psobject.properties... si así lo desea. StrictMode elimina ese beneficio y deja la dificultad de tener que escribir pruebas de existencia. Entonces, en lugar de proporcionar una forma agradable de escribir exactamente una prueba de existencia de miembros, ?. le daría una solución concisa para obtener lo que . siempre hizo. Y si importa que el miembro exista, aún debe codificarlo por separado.

Pero esto me hace preguntar qué pasa con las llamadas a métodos:

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

es decir, ?. se comportaría igual que . para búsquedas de propiedades en modo no estricto, pero se comportaría de manera diferente a . para llamadas a métodos en modo no estricto, lo que lo hace matizado y no un reemplazo directo. ¿Significa eso que al usar ?. no tendría forma alguna de saber si se invocó un método o si no sucedió nada? Las propiedades pueden estar respaldadas por métodos getter, pero creo que es una convención en DotNet que los getters no muten el estado interno, pero es normal que las llamadas a métodos muten el estado. Con ?. ¿no tendría idea de si muta el estado de un objeto?

Me pregunto si puede obtener los beneficios deseados, y mejor, haciendo que ?? pueda manejar las excepciones PropertyNotFoundException y MethodNotFound directamente desde la expresión de la izquierda (pero no otras excepciones planteadas dentro de los métodos), así como también manejar $ nulos y no tener ?. en absoluto. p.ej

$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

Y luego, en lugar de ?. llamar a un miembro o acceder a una propiedad, podría ser una forma concisa de preguntar si existe un miembro, devolviendo un [bool].

Con la misma adición de sintaxis de ?? y ?. podría manejar más situaciones, con una superposición menos confusa.

StrictMode elimina ese beneficio y deja el obstáculo de tener que escribir pruebas de existencia

El obstáculo de una persona es el beneficio de otra:
Todo depende de lo que quieras que suceda _por defecto_:

  • Si está seguro de que no hay _tipos_ en su código, por supuesto, aproveche el comportamiento _default_ (modo estricto APAGADO) - y no necesitará .? (para acceder a la _propiedad_ - consulte siguiente comentario sobre _ llamadas al método_ e _ indexación_).

    • En una nota _personal_: tiendo a usar Set-StrictMode -Version 1 para evitar errores tipográficos en los nombres de _variables_, pero encuentro -Version 2 o superior demasiado molesto, principalmente debido a # 2798 (que es un error que es independiente de esta propuesta).
  • Si desea asegurarse de que (a) no ha escrito mal los nombres de propiedad y / o (b) su código no opera accidentalmente en tipos de datos distintos a los que pretendía operar, configure el modo estricto en la versión 2 o superior .

    • De hecho, eso _actualmente_ hace que sea engorroso _ no aceptar_ estos controles _a petición_,
    • que es precisamente la razón por la que aquí se propone introducir el acceso condicional nulo: para que sea _fácil_ optar por no participar bajo demanda.

Probar explícitamente la presencia de un miembro es realmente un caso de uso separado que puede ser una necesidad independientemente del modo estricto en vigor.

En cuanto a las _ llamadas al método_, que el OP no cubre:

_Llamadas al método_ (por ejemplo, $varThatMayBeNull.Method() ) e _indexing_ (por ejemplo, $varThatMayBeNull[$index] ) son dos casos en los que incluso el modo estricto desactivado o en la versión 1 podría beneficiarse, dado que ambos casos actualmente _invariablemente_ causan un error si el valor al que se accede es $null .

La sintaxis sería la misma que para las propiedades de los métodos - $varThatMayBeNull?.Method() - y análoga para la indexación - $varThatMayBeNull?[$index] - como en C #.

_Update_: Hay un segundo aspecto de la indexación, es decir, si la variable no es nula, pero el elemento en el índice dado no existe (por ejemplo, $arr = 0,1; $arr[2] ). Con el modo estricto versión 2 o inferior, esto se evalúa como $null , pero en la versión 3 o superior provoca un error, y sería bueno poder optar por no aceptar este error también. Sin embargo, la sintaxis para este caso presenta un desafío: vea el OP actualizado, que actualmente propone el quizás incómodo [...?] .

Y, sí, también haría que dicho acceso sea predeterminado en $null , incluso para los métodos; de nuevo, estás _explícitamente_ señalando que está bien no hacer nada si el objeto al que se accede es $null o si no existe tal elemento de matriz.

Tenga en cuenta que C # no tiene indexación condicional nula en el segundo sentido.

Tiene indexación condicional nula, pero no como la propones. C # permite (estoy bastante seguro, al menos ...) array?[0] que omite el problema habitual de "índice en matriz / colección nula" y simplemente devuelve nulo.

Pero sí, estoy de acuerdo en que es una buena idea. Nos ahorra pasar por el manejo de excepciones y mantiene el código bastante claro y conciso.

@ vexx32 , ese es _un_ aspecto de la indexación condicional nula: si array en array?[0] es null , la operación de indexación se ignora; C # también tiene eso, como usted indica.

Estaba (actualización: _también_) hablando del _otro_ aspecto de la indexación condicional nula: el caso en el que array en array?[0] es _no_ null pero es _el elemento en el índice 0 _ que no existe.

Es lo último que no se puede ignorar en C #, que yo sepa, pero creo que también sería útil.

¿Puedes pensar en terminología para dar nombres distintos a estos dos aspectos?

El código de otro problema de JavaScript pasaría de $_.Description[0].Text a $_?.Description[0?]?.Text lo que creo que no es bonito; y mi otra sugerencia sobre cómo se comportaría ?? lo llevaría a $_.Description[0].Text ?? que es subjetivamente mejor y, si es posible implementarlo, manejaría las fallas en cualquier punto de búsqueda en la cadena, todo de una vez , y aún le permite elegir lo que quiere que suceda de forma predeterminada, y tener una alternativa diferente a voluntad en lugar de estar limitado a solo $null .

Aparte, ¿esta sintaxis ?. tendría un análogo para las propiedades y métodos estáticos, es decir, $t = [int]; $t::MaxValu; $t::Pars("1") , se convertiría en ?: o ?:: ?

¿Cuál sería el comportamiento deseado para la indexación de matrices con más de un índice especificado? $array[0,4?,1,2] donde cada uno puede fallar, o $array[0,4,1,2?] con solo el lote completo permitido tener éxito o fallar?

Primero tengo que dar un paso atrás, porque me doy cuenta de que he fusionado aspectos que vale la pena separar, al menos conceptualmente:

  • _Null-value_-conditional member o index access, como en C #:

    • Si un valor al que se accede es $null , ignore los intentos de acceder a sus miembros o indexarlo y evaluarlo en $null .
  • _Member -istence_-conditional member o index access, específico de PowerShell:

    • Si un valor al que se accede es _no- $null _, ignore los intentos de acceder a _miembros_ no existentes (propiedades, llamadas a métodos, indexación) que no existen.

Nota: Para abreviar, estoy usando _member_ de forma algo vaga aquí para abarcar también _elementos_ de objetos que resultan ser colecciones, a las que se accede con _indexing_ en lugar de notación de puntos.

Si está seguro de que no hay errores tipográficos en su código, por supuesto, aproveche el comportamiento predeterminado (modo estricto desactivado) y no tendrá necesidad de hacerlo. (para acceso a la propiedad

@ mklement0 Creo que estás discutiendo desde la vista " una persona que usa el modo estricto para mejorar su propio código " y yo desde la vista " alguien más puede ejecutar mi código en modo estricto, ¿qué cambios harían que mi código también funcione para ellos? "y eso me lleva a un razonamiento diferente. Con ?. sería tan conveniente usarlo en lugar de . y hacer que el código también funcione en modo estricto que también puedo usarlo en todas partes habitualmente; No pierdo nada y gano compatibilidad. Me temo que todo el código de PowerShell se verá afectado de esa manera porque "funciona" en más casos.

Pero no es un reemplazo directo, porque silencia la búsqueda de llamadas de método fallidas en el modo no estricto y silencia las búsquedas de propiedades fallidas en el modo estricto; agrega un matiz complicado a la búsqueda de miembros, una operación increíblemente común. No ayuda a nadie que quiera beneficiarse de las comprobaciones de modo estricto al facilitar esa repetición. No ayuda a suficientes personas en suficientes situaciones, por la complejidad que agrega. Y es demasiado conveniente hacer que el código sea más compatible, no creo que "ignóralo si no lo quieres" sea lo suficientemente fuerte como para mantenerlo a raya.

PowerShell puede hacer cosas que C # no hace, como establecer variables automáticas o tener un precedente de que se produzcan excepciones y se silencien entre bastidores. Tiene que haber un mejor enfoque que no complique la búsqueda de miembros en absoluto, pero simplifica el modelo de control de seguridad en modo estricto para que las personas que quieran usar los controles tengan vidas más fáciles y las personas que se molestaron por los controles también tengan vidas más fáciles.

@HumanEquivalentUnit ¿Cómo silencia estas cosas? Tendría que escribir una carga de manejo de excepciones y verificaciones nulas previamente, en su lugar:

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

v.

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

Y este caso no es infrecuente. O simplemente arroja $ErrorActionPreference = 'Stop' y envuelve todo en try/catch para simplificar la verificación nula, que es un patrón incorrecto (lógica basada en excepciones).

Además, este es el futuro del lenguaje, no es que volvamos a 5.1 y cambiemos las cosas. Si desea más adoptantes, debe facilitar la lectura del código, lo que creo que hace esta sugerencia.

@ mklement0 Creo que estás discutiendo desde la vista "_una persona que usa el modo estricto para mejorar su propio código_" y yo desde la vista "_alguien más puede ejecutar mi código en modo estricto, ¿qué cambios harían que mi código también funcione para ellos? _ "

¿Estamos hablando de "set -euo pipefail" (modo estricto bash) equivalente?

a- Limite las búsquedas de variables (aunque no veo por qué cree que una simple verificación nula en las búsquedas de miembros sería algo malo, la búsqueda de miembros real es mucho más cara que if (result is null) )
b- Use [Strict] en alcances / bloques de código para decirle al analizador que los trate como tales,
c- La rigurosidad se basa en el alcance: el código que no está marcado como estricto no es estricto.

Si escribí un código estricto que falla cuando lo usas, entonces uno de nosotros cometió un error. O hice referencia a una variable faltante en el código que nunca probé o entendiste mal mi API mal diseñada que depende de la existencia de variables que no se pasan a mi función y no pudiste completar una variable que espero que se complete ... .

# 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 función "Registro" no se marcó como estricta, por lo que no se queja del error tipográfico

🤔 Ahora que lo mencionas, un atributo [Strict()] sería una forma _ asombrosa_ de implementar el modo estricto de manera restringida. Eso debe mencionarse en ese otro hilo de problemas sobre problemas de modo estricto, buscaré eso y lo vincularé aquí ...

@ TheIncorrigible1 " ¿Cómo silencia estas cosas? " En modo no estricto $null.x es silencioso, $null.x() es una excepción. Con ?. como se discutió, $null?.x está en silencio, $null?.x() está en silencio.

Entonces tendrías un . que funciona como ?. C #, excepto en modo estricto donde arroja excepciones. Entonces tendrías un ?. que funciona en modo estricto como el ?. C # y como el . PowerShell funciona en modo no estricto, pero que funciona de manera diferente al . PowerShell ?. es claramente mejor y más útil en más de esos escenarios).

Tendría que escribir una carga de manejo de excepciones y verificaciones nulas previamente, en su lugar: $prop = $item?.Method().PropIwant ?? 'PropActionFailed'

La llamada al método puede arrojar, o devolver $ null y es posible que falte PropIWant, aún tendría que escribir:

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

vs con mi ?? (si fuera posible construir), y no hay necesidad de ?. , y cubre posibles casos de excepciones de métodos en caso de que lo único que le interese sea "éxito o no" y sin manejo detallado de errores.

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

Si desea más adoptantes, debe facilitar la lectura del código, lo que creo que hace esta sugerencia.

¿Con qué frecuencia escribe . en PowerShell? ¿Con qué frecuencia desea explicar a los nuevos usuarios cuál es la diferencia entre . y ?. y decirles que tienen que considerar la diferencia cada vez que escriben un . para siempre ?

"Oh, ¿cómo sucedió eso?" "Bueno, en C # . lanzaron una excepción para miembros faltantes, por lo que inventaron ?. que no lo hicieron. Eso fue genial, así que lo hicieron en PowerShell de forma predeterminada, el . no arroja. Luego inventaron el modo estricto que hace que . comporte como C # y arroje, pero solo en ese contexto, pero la forma de verificar manualmente los miembros era realmente prolija y molesta y nadie quería escribirla; en lugar de abordar ese problema de frente y hacerlo más conveniente para beneficiarse del modo estricto, lo esquivaron y imitaron los ?. C # en su lugar para obtener una salida furtiva del rigor que pediste, lo cual es ligeramente conveniente para ti, pero apesta para todos los demás. Y todavía no tienes una prueba de existencia de miembros, y beneficiarte del modo estricto sigue siendo prolijo y molesto, pero al menos no tienes que sufrir eso porque el 'modo estricto' tiene una trampilla de escape del 'modo normal' ahora". Ick.

Si escribí un código estricto que falla cuando lo usas, entonces uno de nosotros cometió un error.

aunque no veo por qué cree que una simple verificación nula en las búsquedas de miembros sería algo malo, la búsqueda de miembros real es mucho más cara que si (el resultado es nulo)

No creo que eso sea malo, el modo no estricto de PS ya lo hace, y creo que sería una alternativa deseable a la propuesta ?. , muy diferente, útil en más situaciones.

Pero tenga en cuenta que en PS puede hacer algo que C # no puede:

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

y sin excepciones en modo no estricto. Cambie los números y vea cuánto tiempo lleva; a juzgar por la actuación y cómo creo que debe funcionar detrás de escena para indexar objetos arbitrarios, parece que en realidad hay ~ 100,000 excepciones que se plantean y silencian, para nuestra conveniencia. PS no siempre hace la opción "debe ser lo más rápido posible, empujar el inconveniente al usuario", y eso me gusta.

@HumanEquivalentUnit Hay muchas características en todos los idiomas que quizás nunca uses en tu carrera y si no te gusta el estilo, está bien, no necesitas usar esas características. No veo por qué estás eliminando el modo estricto; es una buena práctica en los scripts, por lo que está lidiando conscientemente con los problemas en lugar de dejar que el lenguaje se los trague (y, en esencia, tener bloques de captura vacíos implícitos en todas partes). Nuevamente, aún puede no usar las funciones (por ejemplo, nunca usé Out-Default ).

Además, el operador es ? , no ?. ; también funcionaría con acceso a índices.

Para continuar sentando las bases para una mayor discusión, permítanme resumir cómo los modos estrictos existentes afectan el acceso condicional de valor nulo y condicional de existencia de miembros (los términos introducidos anteriormente ):

Las columnas siguientes representan la configuración de Set-StrictMode y los valores de las columnas indican:

  • 👍 ... permitido
  • 🚫 ... prohibido (causa error de terminación de declaración)

Aparte: el hecho de que los errores son solo _statement-_, no _script_-terminating, se relaciona con la discusión más amplia sobre el manejo de errores de PowerShell; consulte https://github.com/PowerShell/PowerShell-Docs/issues/1583.

  • _Acceso condicional de valor nulo - $obj _mismo_ es $null :

Construir | -Off | -Versión 1 | -Versión 2 | -Versión 3+
---------- | ---- | ---------- | ---------- | ------------
$ obj | 👍 | 🚫 | 🚫 | 🚫
$ obj.Prop | 👍 | 👍 | 🚫 | 🚫
$ obj [42] | 🚫 | 🚫 | 🚫 | 🚫
$ obj.Method () | 🚫 | 🚫 | 🚫 | 🚫

Es curioso que con -Off y -Version 1 , $obj.Prop está permitido, mientras que $obj[42] no lo está.

  • _Member -istence_-conditional access - $obj no es $null , pero el miembro / elemento al que se accede no existe:

Construir | -Off | -Versión 1 | -Versión 2 | -Versión 3+
---------- | ---- | ---------- | ---------- | ------------
$ obj.Prop | 👍 | 👍 | 🚫 | 🚫
$ obj [42] (indexable) | 👍 | 👍 | 👍 | 🚫
$ obj [42] (no indexable) | 👍 | 👍 | 🚫 | 🚫
$ obj.Method () | 🚫 | 🚫 | 🚫 | 🚫

Es curioso que los objetos inherentemente indexables (p. Ej., Matrices) permitan el acceso a elementos inexistentes incluso con -Version 2 , mientras que los escalares, donde PowerShell proporciona capacidades de indexación para el manejo unificado con colecciones, no lo hacen.

El operador de remojo nulo (

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

cuando _realmente_ debería poder escribir:

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

Por favor, muchachos, si pudieran obtener solo condiciones nulas de esta propuesta implementada y solo para propiedades, le ahorraría tanto dolor a tanta gente.

Comencé a mirar esto y encontré algunos problemas.

Consideremos ?? y ?=

$x ?= 1 y $x ?? 1 parecen ser sencillos. Pero, dado que son operadores, debemos admitir $x?=1 y $x??1 .

El problema con eso es que $x? y $x?? ambos validan nombres de variables en PowerShell. La única forma de eliminar la ambigüedad sería ${x}?=1 y ${x}??1 .

Y más para el acceso condicional de miembros ?. y ?[] , tendríamos que tener ${x}?.name y ${x}?[0] .
Para estos, $x ?.name y $x ?[0] no serán compatibles.

La otra opción es introducir un cambio importante y no permitir ? en el nombre de la variable en absoluto.

¿Qué piensas? @ mklement0

/ cc @rjmholt @ daxian-dbw @JamesWTruher

Nunca me ha gustado particularmente ni he entendido por qué ? es un nombre de variable válido. Abre la puerta a nombres como $Safe? que en general es más claro y menos incómodo cuando se escribe $IsSafe todos modos.

Creo que ese cambio probablemente haya tardado en llegar.

Abre la puerta a nombres como $ Safe? que generalmente es más claro y menos incómodo cuando se escribe como $ IsSafe de todos modos

Curiosamente expresé el sentimiento opuesto. Es una tradición clásica de Scheme / Ruby .

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

¿No tenía el operador ternario este mismo problema, donde la resolución era requerir espacios alrededor del operador o llaves alrededor del nombre de la variable para que funcione correctamente con variables que terminan en ? ?

Esperaría que con la introducción de estos operadores, PowerShell priorizaría el reconocimiento de ? como parte del operador en una sintaxis como $x?[0] , de modo que los usuarios que usan nombres de variables que terminan en ? para almacenar una colección tendría que usar esta sintaxis en su lugar (ya que los espacios no serían válidos en este caso): ${x?}?[0] . Lo mismo ocurre con $x?.Name y ${x?}?.Name .

¿La otra opción es introducir un cambio rotundo y no permitir? en el nombre de la variable en absoluto.

👍 Dado que este es un cambio de versión importante (6 a 7), creo que vale la pena un cambio radical aquí. Desearía que GitHub tuviera una mejor búsqueda de código para ver cuántas instancias hay de variables PS que terminan con ? . Sospecho que esto no sería tan impactante, pero sería bueno verificarlo con GitHub. En 14 años de uso de PowerShell, nunca he usado ? en el nombre de una variable, pero tal vez sea solo yo. :-)

Ese barco ha zarpado hace mucho tiempo, y no me sorprendería ver variables que terminan con ? en uso en los scripts de hoy.

En este punto, si simplemente priorizamos el análisis de ? como parte de un operador en lugar de como parte de un nombre de variable cuando se trata de estos nuevos operadores, las personas que usan nombres de variables que terminan en ? necesitarían para usar {} o espacios (donde se permiten espacios) para usar esas variables con estos operadores.

Es extraño escuchar la frase "ese barco ha zarpado" en este contexto. Este es un cambio de _ versión importante_. No es descabellado que esto cambie aquí, creo.

@rkeithhill Lo he usado en cosas personales, pero pensé que no estaría claro para el trabajo colaborativo, ya que es muy anti-intuitivo para los programadores tener símbolos como parte de los nombres de variables (similar a usar emojis como variables)

@KirkMunro haber "priorizado el análisis" suena como una puerta abierta a los errores.

@ vexx32 : No es descabellado realizar un cambio importante, ya que se trata de un cambio de versión importante; sin embargo, la barra para tales cambios de ruptura debería permanecer muy alta, y no creo que esto se acerque a pasar esa barra, ya que los usuarios podrían usar variables que terminen en ? siempre que usen {} adjuntos para identificar el nombre de la variable.

Tenga en cuenta que también puede tener un nombre de propiedad que termine en ? . Actualmente, si intenta ver dicha propiedad en PowerShell sin envolver el nombre entre comillas, obtendrá un error del analizador.

Por ejemplo:

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

Estoy un poco sorprendido de que no se analice hoy (¿por qué no se analiza?), Pero de todos modos, para tales propiedades, debe incluir su nombre entre comillas, en cuyo caso podría seguir la cita con un ternario, nulo -coalescente, etc. operador sin espacios y funcionaría bien. Encuentro esta sintaxis muy similar a ${x?}?.name , y estoy de acuerdo con la postura de que puede usar tales nombres de variable / propiedad si lo desea, pero dichos nombres pueden requerir sintaxis o espaciado adicional para funcionar con ternario o nulo - * operadores.

@KirkMunro Nada impide que las personas usen límites variables en el futuro si quieren nombres de variables esotéricos. Estoy de acuerdo con los demás en que me pregunto cuál es el uso actual de ese comportamiento.

Es probable que los usuarios de PowerShell 7 ya sean entusiastas y estén al tanto de los cambios importantes. Las personas que no lo están, siguen usando <= v5.1 y continuarán haciéndolo durante mucho tiempo; probablemente hasta que msft lo elimine de Windows 10 (nunca).

@KirkMunro Seguro, pero eliminarlo de los caracteres de variable permitidos estándar no evita que los usuarios simplemente hagan ${Valid?} como nombre de variable de todos modos. Dado que tendrían que hacer eso con estos operadores independientemente, creo que sería mejor que sea consistente, en lugar de que ? convierta en un carácter que _sólo a veces_ se considera parte de un nombre de variable.

Eso ya será un cambio radical, y creo que es mejor al menos ser coherente al respecto e ir hasta el final en lugar de introducir otro nivel de ambigüedad. 🙂

@adityapatwardhan creo que sería mejor para el idioma eliminar ? como un carácter variable válido. Permitiría fácilmente operadores ternarios y de remojo / coalescencia nulos en una sintaxis familiar que agrega mucha ergonomía al proceso de creación de scripts.

Que @KirkMunro tenga "análisis priorizado" suena como una puerta abierta para errores.

@ TheIncorrigible1 : Cualquier código puede abrir la puerta a errores si no se implementa correctamente. Solo estoy hablando de una búsqueda anticipada simple de un solo carácter para identificar si PowerShell se encuentra con un operador ternario o nulo- * cuando analiza un nombre de variable que no está encerrado en límites de variable y encuentra un carácter ? . Eso no es complicado y no abre la puerta a más errores que cualquier otro cambio de código.

Es probable que los usuarios de PowerShell 7 ya sean entusiastas y estén al tanto de los cambios importantes. Las personas que no lo están, siguen usando <= v5.1 y continuarán haciéndolo durante mucho tiempo; probablemente hasta que msft lo elimine de Windows 10 (nunca).

@ TheIncorrigible1 : ¿Qué base / evidencia tiene de esa afirmación? PowerShell 7 está en versión preliminar, por lo que hoy solo lo usan los entusiastas. Eso es un hecho. Pero más allá de la versión preliminar, si PowerShell 7 o una versión posterior ofrecen características atractivas que las empresas necesitan, al mismo tiempo que admiten la funcionalidad que necesitan, utilizarán esas versiones. Eso es especialmente cierto si PowerShell 7 se instala con el sistema operativo. El único punto en el que entran en juego los entusiastas es en las organizaciones que no tienen una necesidad comercial de lo que PowerShell 7 trae a la mesa.

Eso ya va a ser un cambio radical, y creo que es mejor al menos ser coherente al respecto y llegar hasta el final en lugar de introducir otro nivel de ambigüedad. 🙂

@ vexx32 Eso es estirarlo. Sería un cambio importante si tuviera ?? en el nombre de una variable, pero la probabilidad de que sea así es mucho más remota que tener una variable cuyo nombre termina en un solo ? . Aparte de eso, ¿cómo sería la introducción de operadores nulo- * sin dejar de admitir ? como una variable estándar permitida en los scripts de rotura de caracteres?

En mi experiencia, los cambios de ruptura para los agradables (que es lo que parece ser) son, con mucha frecuencia, rechazados, y la discusión / argumentos en torno a ellos solo sirven para ralentizar el proceso de hacer las cosas de manera espectacular, para el punto en el que las cosas simplemente se estancan o no llegan a un lanzamiento, etc. La desaceleración suele ser necesaria, porque si está proponiendo un cambio radical, se necesitan pruebas para poder evaluar el impacto y justificar dicho cambio. Es difícil reunir esa evidencia hoy. Solo digo esto porque elegiré terminar las funciones ahora en lugar de discutir sobre un cambio importante que es bueno tener cualquier día.

Sin embargo, nunca uso ? en nombres de variables, ni lo haría yo. Sin embargo, espero que algunas personas lo hagan, porque se puede leer muy bien en un script y poner barreras innecesarias de entrada para PowerShell 7 solo ralentiza la adopción. especialmente cuando muchas personas que trabajan con PowerShell no son desarrolladores que estén más acostumbrados a trabajar con cambios importantes.

De todos modos, no es mi intención ralentizar este proceso, sino todo lo contrario. Pero he compartido mis pensamientos y mi experiencia, por lo que no comentaré más sobre si deberíamos presionar o no para lograr un cambio radical aquí.

Considere este ejemplo artificial:

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

Este comportamiento _ya_ rompería con los cambios propuestos. Preferiría una ruptura constante y limpia que una ruptura confusa que necesita una explicación de media página para enumerar todas las posibles excepciones y cuándo y dónde ? repente no es válido y dónde todavía lo está.

@KirkMunro si PowerShell 7 o una

Habiendo trabajado en algunas Fortune 50 con algunas bases de empleados de cientos de miles, incluso alejarse de lo que era predeterminado en el sistema operativo fue un desafío (es decir, pasar a v5.x). Todavía no he visto ningún lugar adoptar Core ; prefieren pasar a Python para compatibilidad cruzada. Habilitar las funciones opcionales de Windows también fue una tarea bastante rara.

Creo que las empresas trabajan con lo que tienen y la base de conocimientos de sus empleados en busca de nuevas tecnologías o versiones lingüísticas para resolver sus problemas. Algunos estarían perfectamente contentos si permanecieran en v2 para siempre y nunca tocarían los cmdlets Win10 / Server16 que hacen la vida mucho más fácil.

Mi punto con todo esto es que estas características no están en el vacío. Si hace un lenguaje más ergonómico, verá una mayor adopción por parte de las personas interesadas en la herramienta para resolver los problemas que tienen más rápido. (Ver: C # y el crecimiento en popularidad con más / mejores características de lenguaje)

Con respecto a las variables que terminan en ? , ¿podría ser un cambio significativo debido a la variable automática $? .

@lzybkr Sospecho que el mejor caso para lidiar con eso es un caso especial como el que ya existe para $^ y $$ .

@lzybkr @ TheIncorrigible1 Por lo que recuerdo, _todas_ esas variables están explícitamente en mayúsculas especiales en el tokenizador. $^ _already_ no es un nombre de variable válido. El tokenizador tiene casos especiales para todos aquellos antes de comenzar a buscar nombres de variables estándar.

La única solución aquí es usar ¿ :

$ tonto? ¿= 1

No sé Steve, estoy firmemente entre la multitud interrogada sobre este.

$silly?‽=1

@lzybkr - que yo sepa, $? $$ y $^ se tratan de una manera especial.

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

Para resumir, tenemos estas cuatro opciones

  • Gran cambio importante: no permita ? en los nombres de las variables.
  • Prefiere ?. como operador. Esto significa que los nombres de variables que terminan en ? deben usar la sintaxis ${variablename} . Sigue siendo un cambio decisivo.
  • Prefiere el comportamiento antiguo. Esto significa que debe usar ?. y ?[] , ${variablename}?.property . Sin cambios importantes, pero hace que el uso de los nuevos operadores sea torpe.
  • No implemente los nuevos operadores.

Yo personalmente, no prefiero el primero y el último.

Este es un cambio de versión importante. No es descabellado que esto cambie aquí, creo.

Creo que un punto importante a destacar es que la versión principal se está incrementando para indicar que está listo para reemplazar Windows PowerShell, es decir, indica compatibilidad, no rotura. Del anuncio original :

Tenga en cuenta que la versión principal no implica que vayamos a realizar cambios importantes.

¿Las opciones 1 y 2 no son iguales? ¿O todavía se permitiría a las variables usar ? en el caso de que no haya un operador ternario o coalescente nulo siguiéndolas?

Si es así, creo que podemos tener muchos problemas para manejar la lógica de tokenización / análisis sin mucho retroceso. Esto puede provocar degradaciones en el rendimiento cuando las variables terminan en ? .

Dado que, por lo que puedo ver, la opción 2 parece ser la preferencia general, no estoy realmente seguro de entender la renuencia a hacer el cambio radical aquí. Hacerlo de esa manera desalentará activamente el uso de ? en nombres de variables de todos modos, simplemente presentando escenarios en los que no se pueden usar sin incluir el nombre de la variable.

Creo que este es un cambio bastante menor a medida que avanzan los cambios importantes, y tener una ruptura en la consistencia de lo que se puede y no se puede usar en un nombre de variable es probablemente la peor opción, en mi opinión.

Estas cosas deben tener reglas claras que se apliquen en casi todas las situaciones. Actualmente, este es el caso. Estamos proponiendo enturbiar las aguas aquí y dejar el comportamiento menos claro. No puedo ver nada bueno de eso, excepto quizás que los nombres de variables que contienen ? vuelven menos usados ​​simplemente porque son más difíciles de usar en algunos escenarios, lo que (efectivamente) nos lleva de regreso a la opción 1 por defecto, casi ... así que no veo ninguna razón en particular para no tomar el descanso ahora y simplemente evitar el comportamiento ambiguo.

@ vexx32 Existe una ligera diferencia entre 1 y 2.

Para el # 1 no permitimos que ? se use en nombres de variables todos juntos. Esto significa que $x? = 1 , $x?? = 1 $x?x?x = 1 no se analizarán.

Para el número 2, $x? = 1 sigue siendo válido, pero $x?.name es equivalente a ${x}?.name . Esto solo rompe los nombres de las variables con ? al final, que son miembros de acceso. Entonces, $x? = 1 , $x?? = 1 $x?x?x = 1 aún serían válidos.

Sí, estaría un poco preocupado por tokenizar los gastos generales allí. Podría valer la pena implementar ambas posibilidades y hacer algunos puntos de referencia en un script que usa nombres de variables similares razonablemente en gran medida.

Mi preferencia es definitivamente la opción 1 ... un cambio de ruptura único es, al menos para mí, mucho más preferible que tener que lidiar con las inconsistencias en cómo se puede analizar en el futuro.

Si es así, creo que podemos tener muchos problemas para manejar la lógica de tokenización / análisis sin mucho retroceso. Esto podría provocar una degradación del rendimiento cuando las variables terminan en?.

Comparto esta preocupación por esa posibilidad. Tener ? como separador de tokens a veces me parece una línea irregular en el idioma.

Si es así, creo que podemos tener muchos problemas para manejar la lógica de tokenización / análisis sin mucho retroceso. Esto podría provocar una degradación del rendimiento cuando las variables terminan en?.

Depende de cómo lo implementes. Siempre que adopte un enfoque de anticipación en lugar de un enfoque de tokenización y luego de respaldo, debería estar bien. Puede mirar hacia adelante para ver qué caracteres son los siguientes cuando encuentre un ? en el nombre de una variable y tomar una decisión sobre cómo desea "envolver" el token de variable en función de lo que sigue. Eso no es un gran problema y no debería requerir un retroceso o dar como resultado una degradación notable del rendimiento.

@ PowerShell / powershell-Committee revisó este hoy, tenemos un par de pensamientos:

  • No importa lo que hagamos, vamos a hacer un análisis de nuestro corpus de scripts para ver con qué frecuencia la gente usa ? en nombres de variables
  • Algunos de nosotros tenemos una hipótesis (que a otros les gustaría validar) de que los usuarios que están usando ? en sus nombres de variables pueden ser usuarios menos avanzados (como acordamos en esta sala, nos mantendríamos alejados porque de los posibles problemas que pudieran surgir). Por otro lado, cualquiera que use la funcionalidad descrita aquí podrá comprender una sintaxis un poco más complicada (como ${foo}?.bar ). Por lo tanto, preferimos la opción 3 porque evita cambios importantes en estos usuarios menos experimentados. (Pero nuevamente, lo validaremos según la primera viñeta).
  • @ daxian-dbw planteó un buen punto sobre la dificultad de encontrar todas las referencias de variables cuando los scripters están mezclando el uso de $foo y ${foo} . Sin embargo, acordamos que esto se puede solucionar en las herramientas (como la extensión VS Code PowerShell), y los usuarios como @JamesWTruher que usan editores como Vim pueden hacer coincidir fácilmente ambos con su sintaxis de búsqueda.

es más difícil encontrar todas las referencias de variables cuando los scripters combinan el uso de $ foo y $ {foo}

Eso depende de si el AST diferencia el nombre de la variable en función de si vio las llaves. Sospecho que cualquier herramienta que use PowerShell AST no tendrá problemas con los frenos aquí.

Pero para las expresiones regulares, ciertamente significa que debe ser más consciente: varname -> \{?varname\}?

@rjmholt Hice un análisis aquí . Un desglose rápido: de casi 400,000 scripts con más de 22,000,000 de nombres de variables (no únicos), solo había ~ 70 variables únicas que terminaban en ? .

Gracias, @mburszley - para mí, eso lo convierte en un Bucket 3: cambio de {...} es muy desafortunado, en paralelo con la desafortunada necesidad de $(...) alrededor de exit / return / throw declaraciones en el contexto de && y || .

Para tomar prestado el razonamiento de ese tema:

Si forzamos el uso de {...} alrededor de nombres de variables solo para que pueda usar ?. :

  • Los nuevos usuarios no esperarán la necesidad de {...} y no sabrán necesariamente que _it_ es lo que se requiere cuando lo siguiente falla (posiblemente _undetected_, a menos que Set-StrictMode -Version 2 o superior esté en efecto): $o = [pscustomobject] @{ one = 1 }; $o?.one

  • Incluso una vez que los usuarios _saben_ la necesidad de {...} :

    • Se olvidarán de usarlo en ocasiones, debido a la necesidad contraintuitiva de hacerlo.
    • Cuando lo recuerden, este requisito aparentemente artificial será una fuente constante de frustración, especialmente porque {...} es difícil de escribir.

Este problema se ha marcado como solucionado y no ha tenido actividad durante 1 día . Se ha cerrado por motivos de limpieza.

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

no romper la forma en que analizamos la sintaxis válida existente era el camino correcto a seguir. Una vez más, un cambio no es solo un caso en el que tomemos la decisión de apoyar una pequeña cantidad de programas salvajes; hemos realizado numerosos cambios importantes en los casos en los que pensamos que los pros superaron los contras (no es que yo esté de acuerdo personalmente con todos ellos, o que esos justifican o no a otros). El problema es que cambiar algún aspecto del tokenizador o analizador significa que dos versiones de PowerShell ya no generarán el mismo AST para algunos scripts, por lo que dos PowerShells "verán" el mismo script de manera diferente. Eso significa que ni siquiera podemos leer la sintaxis de la misma manera, por lo que no hay una regla de PSScriptAnalyzer que pueda escribir para detectar posibles problemas relacionados con ella; PSScriptAnalyzer verá una sintaxis diferente de una versión de PowerShell a la siguiente.

A diferencia de C #, PowerShell no puede precompilar una sintaxis diferente a un formato compatible para su ejecución posterior, lo que significa que un cambio sintáctico está vinculado al tiempo de ejecución. Una vez que PowerShell hace una ruptura sintáctica, reducimos la cantidad de scripts que pueden funcionar en diferentes versiones, lo que significa que los usuarios se ven obligados a escribir dos scripts, lo cual es un problema serio para un shell y un lenguaje de scripting. Se supone que PowerShell es lo suficientemente dinámico como para superar todas las diferencias con la lógica dentro de un script, pero la sintaxis es la única cosa estática no negociable que tenemos. Y hacer un cambio de sintaxis donde tanto el antes como el después son válidos es especialmente pernicioso, ya que no hay una forma sencilla de detectarlo, no hay advertencia para ello e incluso después de ejecutarlo en ambos entornos, es posible que los usuarios no sepan que ocurrió un comportamiento diferente.

En general, puedo apreciar que tales cambios pueden ser muy problemáticos y solo deben realizarse si los pros superan los contras, un factor importante de los cuales es cuánto se rompe el código existente.

reducimos la cantidad de scripts que pueden funcionar con diferentes versiones
lo que significa que los usuarios se ven obligados a escribir dos scripts

Estamos hablando de una función sintáctica _nuevo_ aquí ( ?. ), por lo que, por definición, los scripts que lo usan _no pueden_ (significativamente) ejecutarse en versiones anteriores, a menos que agregue específicamente condicionales que proporcionen rutas de código compatibles con versiones heredadas, pero no parece que valga la pena, entonces simplemente se quedaría con las funciones heredadas.

Sí, la interpretación de $var?.foo en scripts antiguos que usaban $var? como nombre de variable se rompería, pero:

  • ? nunca se debería haber permitido como parte de un identificador _ sin encerrarlo en {...} _.

  • Dado que poder hacerlo es inesperado y probablemente incluso _desconocido_ para muchos, tales nombres de variables son extremadamente raros en la naturaleza, hablando por experiencia personal, pero el análisis de @mburszley proporciona evidencia más tangible .

    • Incluso Ruby solo permite ? (y ! ) al final de los identificadores, y solo de identificadores de método, y sospecho que la mayoría de los usuarios de Ruby saben que no deberían asumir que otros idiomas admiten la misma cosa.

Entonces, pragmáticamente hablando:

  • La gran mayoría del código existente no se verá afectado: un token como $var?.foo simplemente no se encontrará.

  • Si escribe $var?.foo con la nueva semántica, entonces sí, ejecutar eso en versiones anteriores podría resultar en un comportamiento diferente (en lugar de romperse de una manera obvia), dependiendo del modo estricto que esté en efecto, pero _ siempre debería hacer cumplir la versión mínima requerida para ejecutar su código como se pretende de todos modos_ ( #requires -Version , claves de manifiesto del módulo).

En general, para mí, este es un caso claro de un cambio de cubo 3: un cambio técnicamente rompedor que rompe muy poco código existente al tiempo que ofrece beneficios reales (o, por el contrario, evita dolores de cabeza perennes debido a un comportamiento inesperado).

@ mklement0 mantenemos el acceso nulo-condicional experimental para PS7.0. ¿Quizás pueda abrir un nuevo número para continuar esta discusión para 7.1?

Suena bien, @ SteveL-MSFT; consulte el número 11379.

Animo a todos los que están aquí a volver a mostrar su apoyo (o, jadeo, no apoyo) allí.

¿Fue útil esta página
0 / 5 - 0 calificaciones