Powershell: Sugerencia: implementar condicionales ternarios

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

Los condicionales ternarios de estilo C serían una adición útil al lenguaje.

Por ejemplo, en lugar de escribir:

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

se podría escribir:

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

También aliviaría una decepción de larga data:

En Microsoft, "enviar es elegir". Una de las cosas que nos decepcionó mucho al no poder enviar en V1.0 es un operador ternario.

De una publicación de blog del equipo de PowerShell con fecha del 29 de diciembre de 2006.


Relacionado: implementar asignaciones de coalescencia nula y remojo de nulos y condicionales nulos

Committee-Reviewed Issue-Enhancement WG-Language

Comentario más útil

@RichardSiddaway : Si miramos Stack Overflow en preguntas etiquetadas con PowerShell _preguntas desde 2014_, obtenemos (al momento de escribir este artículo):

$PSItem se introdujo en la v3 en septiembre de 2012, por lo que, para estar seguro, elegí 2014 como fecha de inicio de la consulta.

Si bien esta no es una métrica exacta, el sitio no le permite buscar $_ o _ , desafortunadamente, y estoy seguro de que hay preguntas que contienen _ninguno_ $_ ni $PSItem , y todavía se están haciendo preguntas anteriores a la v3; todavía creo que es seguro concluir que $_ se usa con mucha más frecuencia que $PSItem .

Sin embargo, el punto más importante es que no es necesario _eligir_:

Así como $PSItem y $_ coexisten felizmente, también lo hacen ForEach-Object y % , Where-Object y ? , .. .:

$a ? $b : $c pueden coexistir con if ($a) { $b } else { $c } / $(if ($a) { $b } else { $c })

En cuanto a recapitular las razones _positivas_ para introducir $a ? $b : $c

  • más conciso, menos desordenado visualmente, utilizando una sintaxis familiar para la mayoría de los programadores.

  • más eficiente, porque no hay necesidad de $(...) , que las declaraciones if necesitan para permitir su uso como parte de una expresión más grande (que es más ruidosa, menos eficiente y puede tener un lado no deseado efectos)

En cuanto a la preocupación por la oscuridad:

Se puede suponer que alguien que escribe _expresiones_ (en lugar de simplemente _invocar comandos_ con argumentos (simples)) tiene algo de experiencia como desarrollador, y mi sentido (anecdótico) es que la mayoría de los desarrolladores al menos _reconocen_ $a ? $b : $c como if condensados

Incluso si no lo hacen, sin embargo, se explica fácilmente, y aparte del uso de _símbolos_ no obvios, la complejidad conceptual es la misma que la de un if ($a) { $b } else { $c } , e incluso menor que
$(if ($a) { $b } else { $c })

Suponiendo que se da cuenta una vez introducido (sin duda, esta discusión muestra que hay demanda), encontrarlo con frecuencia lo convertirá en un idioma familiar y fácilmente reconocible (que es más conciso, más fácil de escribir y, al menos para mí y para algunos otros aquí, más legible), al igual que la mayoría de la gente parece preferir $_ sobre $PSItem .

Todos 52 comentarios

Tenga en cuenta que con el cambio para permitir asignaciones de declaraciones, se reduce la necesidad de un operador ternario. Simplemente puedes hacer
$var = if ($x) { $x } else { $y }
No es tan conciso como el operador ternario, pero podría decirse que es más legible.

Sí, aunque todavía tiene que usar $(...) _ además_ si el condicional es parte de una expresión más grande:

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

vs.

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

Sé que la legibilidad está en el ojo del ... eh ... lector, pero personalmente encuentro esto último visualmente más fácil de analizar, y tener que escribir menos es siempre una ventaja.

Con una función de uso tan frecuente, creo que recordar la sintaxis ternaria más abstracta no sería un problema (y, por supuesto, la gente puede seguir usando if , si así lo prefieren).

@ mklement0 Tengo que estar de acuerdo más tarde tiene menos carga cognitiva.

Definitivamente está en mi lista de favoritos.
@BrucePay , ¿hay alguna razón por la que esto sea una mala idea? ¿O se trata simplemente de 'enviar es elegir'?

En el pasado, esta solicitud de función se rechazó por ser más difícil de entender para los guionistas menos experimentados, y que la forma de expresión de la declaración if era una alternativa más clara, aunque más detallada.

Mi perspectiva personal: si el idioma fuera solo para mí, probablemente lo habría agregado hace mucho tiempo. Pero ... encuentro que muchos desarrolladores no lo usan, lo que en realidad sugiere que hay algo de verdad en la hipótesis de que las personas con menos experiencia tendrán problemas con el operador ternario.

@lzybkr :

Vale la pena distinguir entre el _ uso activo_ de una característica frente a la capacidad de _reconocir_ y comprenderla.

Claramente, todo el mundo puede elegir si desea utilizar dicha función, pero ¿está diciendo que "tener problemas con" significa que las personas con menos experiencia no lo _ entenderán_ cuando lo vean en el código de los demás?

@ mklement0 : presentamos $psitem como un alias para $_ debido a la retroalimentación suficiente de que $_ era críptico y confuso, por lo que creo que el operador ternario sería difícil para algunos menos personas experimentadas para entender.

Por otro lado, hay muchos elementos en PowerShell que son confusos para los principiantes o incluso para los desarrolladores bastante experimentados.

Al igual que con cualquier otro idioma, se necesita algo de esfuerzo para aprender la sintaxis y el significado de las construcciones del lenguaje.
No sé si creo que el operador ternario es especialmente difícil de entender.

¿Tiene datos que sugieran que sí?

Creo que los únicos datos son anecdóticos, pero la crítica se aplica a cualquier lenguaje críptico: bash, perl, etc.

Y para ser claro, estaba proporcionando el contexto histórico. Quizás PowerShell sea lo suficientemente omnipresente ahora que una sintaxis más críptica no afectará la adopción.

También tenga en cuenta que algunos lenguajes concisos todavía usan if / then como operador ternario, por ejemplo, F #.

Dicho esto, tal vez sea posible usar menos caracteres y no ser demasiado críptico:

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

-then/-else encaja bien con la sintaxis de PowerShell, pero, un operador (u operadores si es demasiado confuso para pensar en un solo operador), obtiene el beneficio de no necesitar paréntesis ni llaves.

Por otra parte, esto está buscando problemas similares a foreach frente a foreach-object . pero tal vez no sea tan malo, no lo sé.

@lzybkr :

Críptico en dosis homeopáticas es saludable:

PowerShell es encomiablemente no críptico en general, pero en algunos casos ofrece una sintaxis críptica como una _alternativa_ concisa (aún puede ser detallado si lo desea) para construcciones _ de uso frecuente_, en particular ? por Where-Object y % por ForEach-Object .

Proporcionarme $x ? $y : $z como una alternativa concisa a if ($x) then { $y } else { $z } está en el mismo espíritu.

El aspecto críptico mejora porque ? recuerda a una _ pregunta_ y, por lo tanto, sugiere un condicional (aunque uno _ precede_ al ? en este caso) y, lo que es más importante, es _ una construcción potencialmente familiar de varias otros lenguajes_, con la misma semántica fundamental.

No obtiene el mismo beneficio con $x -then $y -else $z : no es familiar.

Además, aunque muchos operadores de PS tienen nombres simbólicos, muchos no: * / + % ...
Estos también son intrínsecamente crípticos, simplemente ya no los percibimos de esa manera, porque son muy familiares y omnipresentes.

Mi sensación es que $x ? $y : $z también ya es familiar para muchos, y lo será aún más una vez que se introduzca en el lenguaje, dada la necesidad frecuente de condicionales concisos.

Tenga en cuenta que estará bastante limitado en lo que puede especificar con este operador. En particular, no podrá usar comandos a menos que los ponga entre paréntesis:

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

comparado con

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

o

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

vs

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

En mi opinión, hay pocas ventajas en términos de brevedad y una clara desventaja en la legibilidad. El operador ternario es mucho menos interesante cuando tienes un lenguaje orientado a expresiones. Cuando comencé con el lenguaje hace 16 años, agregar el operador ternario parecía obvio viniendo de un fondo de C. Ahora me alegro de que nunca lo hayamos agregado. Simplemente se siente como un desorden.

En particular, no podrá usar comandos a menos que los ponga entre paréntesis:

Eso se aplica a _cualquier_ operador de PowerShell.

No todas las declaraciones de PowerShell involucran comandos, y cuando lo hacen, los usuarios ya saben que (...) es el precio de admisión para los comandos (en la mayoría de los casos).

En su propio ejemplo, para mí ((test-path foo.txt) ? "foo.txt" : "bar.txt") gana a $(if (test-path foo.txt) {"foo.txt"} else {"bar.txt"}) , tanto por la oscuridad de necesitar $(...) como por el ruido introducido por las llaves.

Tal vez sea solo yo, pero encuentro esto:

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

mucho más fácil de escanear / analizar visualmente que esto:

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

Mi única queja sobre este problema es que si vas a hacer ?: ternarios, también deberías hacer ?? fusión nula:

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

He visto varias implementaciones Invoke-Ternary e Invoke-NullCoalescing en la naturaleza (por ejemplo, https://github.com/dahlbyk/posh-git/blob/master/src/Utils.ps1#L12). Eso indica que hay un deseo general de que tal característica incorpore el lenguaje.

@rkeithhill : estoy de acuerdo; re coalescencia nula: ya existe un problema, que también cubre el remojo nulo: # 3240

Por lo tanto, el argumento de los codificadores menos experimentados no podría usar fácilmente una declaración de código ternario o de fusión nula que creo que es un poco miope. No hay ningún requisito para usar estas funciones "avanzadas" y si un programador no puede leer el código porque carece de experiencia, entonces personalmente esa es mi señal de que necesito aprender algo nuevo realmente rápido.
Cuando vi por primera vez un ternario en C #, pensé que WTF es este nuevo infierno que ha introducido MS, hasta que me tomé unos minutos para leer sobre esto, que luego me enganchó.

Ejemplo práctico en POSH, tengo esta línea:
$mc_object = ($Message.fields | where Name -Match appname).Content
lo cual está bien y excelente, excepto cuando el objeto $ Message no tiene una propiedad archivada que tiene un nombre de "nombre de la aplicación", y como no controlo los datos formateados JSON de los que proviene, tengo que determinar qué hacer.

Entonces, con operaciones de fusión nula, todo lo que tengo que hacer es agregar ?? "" al final para asegurarme de que $ mc_object siempre sea una cadena válida, incluso si el establecedor original fue nulo. De lo contrario, tendría que hacer algunas técnicas diferentes para lograr lo que pueden hacer 4 pulsaciones de teclas, como
$mc_object = if(-not ($Message.fields | where Name -Match appname).Content)){""}else{($Message.fields | where Name -Match appname).Content}
Eso para mí es muy ilegible, pero luego puedo limpiar esto un poco haciendo algo como esto, que es lo que estoy haciendo.
$mc_object = ($Message.fields | where Name -Match appname).Content if(-not $mc_object){$mc_object = ""}

Si bien no es terrible, es mucho más de 4 teclas presionadas para nulo-coelasce.

De todos modos, definitivamente voto por ternario y coelasce nulo en Powershell, agrega algunas características muy avanzadas y hace que Powershell sea más atractivo para usar en la forma "central" en cualquier sistema.

@lzybkr Aún no he visto a nadie adoptar $PSItem . Trabajo en un equipo bastante grande de personas que escriben scripts y todavía usan $_ , incluso los usuarios de PowerShell con menos experiencia.

@tibmeister o ....

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

Las asignaciones como expresiones pasarán, pero son increíblemente ilegibles.

Yo uso regularmente $ psitem

Durante varios años de evaluación de Scripting Games, $ psitem se usó mucho en las respuestas.

@RichardSiddaway : Si miramos Stack Overflow en preguntas etiquetadas con PowerShell _preguntas desde 2014_, obtenemos (al momento de escribir este artículo):

$PSItem se introdujo en la v3 en septiembre de 2012, por lo que, para estar seguro, elegí 2014 como fecha de inicio de la consulta.

Si bien esta no es una métrica exacta, el sitio no le permite buscar $_ o _ , desafortunadamente, y estoy seguro de que hay preguntas que contienen _ninguno_ $_ ni $PSItem , y todavía se están haciendo preguntas anteriores a la v3; todavía creo que es seguro concluir que $_ se usa con mucha más frecuencia que $PSItem .

Sin embargo, el punto más importante es que no es necesario _eligir_:

Así como $PSItem y $_ coexisten felizmente, también lo hacen ForEach-Object y % , Where-Object y ? , .. .:

$a ? $b : $c pueden coexistir con if ($a) { $b } else { $c } / $(if ($a) { $b } else { $c })

En cuanto a recapitular las razones _positivas_ para introducir $a ? $b : $c

  • más conciso, menos desordenado visualmente, utilizando una sintaxis familiar para la mayoría de los programadores.

  • más eficiente, porque no hay necesidad de $(...) , que las declaraciones if necesitan para permitir su uso como parte de una expresión más grande (que es más ruidosa, menos eficiente y puede tener un lado no deseado efectos)

En cuanto a la preocupación por la oscuridad:

Se puede suponer que alguien que escribe _expresiones_ (en lugar de simplemente _invocar comandos_ con argumentos (simples)) tiene algo de experiencia como desarrollador, y mi sentido (anecdótico) es que la mayoría de los desarrolladores al menos _reconocen_ $a ? $b : $c como if condensados

Incluso si no lo hacen, sin embargo, se explica fácilmente, y aparte del uso de _símbolos_ no obvios, la complejidad conceptual es la misma que la de un if ($a) { $b } else { $c } , e incluso menor que
$(if ($a) { $b } else { $c })

Suponiendo que se da cuenta una vez introducido (sin duda, esta discusión muestra que hay demanda), encontrarlo con frecuencia lo convertirá en un idioma familiar y fácilmente reconocible (que es más conciso, más fácil de escribir y, al menos para mí y para algunos otros aquí, más legible), al igual que la mayoría de la gente parece preferir $_ sobre $PSItem .

mklement0, tienes un ejemplo muy impresionante y creo que demuestra el punto claramente, gracias.

Releyendo y revisando esto y mirando algunas de las preguntas, me encuentro inclinándome más hacia las sintaxis un poco más detalladas sugeridas:

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

o, para una sintaxis más legible semánticamente:

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

@ vexx32 Si bien no me importa su primer ejemplo, encuentro que la condición en medio de una expresión es extremadamente pesada.

Sí, creo que estoy de acuerdo, pero leí un poco más ... sin problemas. Pero todavía tendía a ir a la primera.

Dado que PowerShell está destinado a ser un lenguaje "en rampa" para C #, creo que usar ? : es el camino a seguir. Incluso JavaScript usa esta sintaxis y es uno de los lenguajes más populares en estos días. :-)

De acuerdo, @rkeithhill , tanto por la familiaridad de la construcción de varios otros lenguajes _y_ el deseo de tener también asignaciones de coalescencia nula, absorción de nulos y condicionales nulas , que en C # también se basan en ? .

Los dos últimos, por ejemplo, $foo?.bar y $var ?= 'default val' , no son realmente posibles sin una representación basada en símbolos, e incluso para $a ?? 'value-if-null' fusión nula parece preferible a algo como $a -elseifnull 'value-if-null' .

Recuerde que ? , como un alias de uso frecuente para Where-Object , ya está firmemente arraigado como representante de un _condicional_, por lo que parece lógico transferir ese conocimiento a variaciones de su uso.

¿Es PowerShell realmente una vía de acceso a C #? Sé que fue una intención declarada hace 10-12 años, pero ¿realmente está sucediendo? Mi sospecha es que para la mayoría de los usuarios de PowerShell, C # no es un lugar al que quieren ir.

si van a ocurrir condicionales ternarios, preferiría ver algo como
$ valor = $ trueVal -if $ a -eq $ b -else $ falseVal

como lo menciona @ vexx32

Tiene más sentido para el usuario medio de PowerShell.

@ mklement0 Mis comentarios sobre $ psitem se basaron en mi experiencia personal. Si ha tenido una experiencia diferente, no invalida mi experiencia.

Sé que fue una intención declarada hace 10-12 años.

Sí, en las primeras cumbres MVP entre otros lugares de Jeffrey. No he escuchado nada diferente desde entonces.

Además, casi todas las construcciones condicionales / de bucle toman de C # (y el linaje C), if {} , while {} , do {} while , switch {} , por {} , foreach {} , intente {} atrapar {} finalmente {} `. Para mí tiene sentido que esta construcción condicional también lo tenga.

Sin embargo, esas son palabras clave de idioma, @rkeithhill. Los operadores son completamente diferentes.

Creo que encontrará que la gran mayoría de los operadores utilizados en PowerShell son bastante diferentes de sus equivalentes de C #. El equipo de PS ha optado muy claramente por una sintaxis más descriptiva para la mayoría de los operadores.

Consideraría que el comportamiento ternario también debería seguir las opciones de sintaxis más detalladas disponibles. PowerShell puede haber sido concebido como una 'vía de acceso' a C #, pero eso no significa que deba heredar sus sintaxis más simbólicas. De hecho, hay muchos lugares donde eso se ha evitado minuciosamente.

Considere, si lo desea, que sus argumentos a favor de la sintaxis simbólica se basan en cómo otros lenguajes de programación comunes representan este concepto. PowerShell no ha seguido ese camino en la publicación, sino que ha preferido trabajar con una sintaxis tan descriptiva como sea posible. El simple hecho de que aquellos en uso que ya tienen experiencia en C # estén familiarizados con dicha sintaxis no es sin duda una razón para usarla.

Si PowerShell es un lenguaje de 'rampa' a C # o cualquier otro idioma (que, siento, lo hace bastante bien en este momento), entonces tenemos que considerar el mínimo común denominador aquí y pensar en lo que la mayoría de las personas sin experiencia encontrarían sensible e intuitivo .

No estoy diciendo que mis soluciones ofrecidas son, pero yo creo que están posiblemente se dirigieron en una dirección más sensata desde esta perspectiva.

@ vexx32
¿Qué hay de estos operadores?

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

En general, estoy de acuerdo en que seguir el ejemplo de C # no siempre es apropiado y que debe tener prioridad la preservación del espíritu de PowerShell.

Por el contrario, desaconsejaría desviarse de C # en los casos en que la misma sintaxis parezca un ajuste plausible, y para mí, la propuesta en cuestión, junto con # 3240, es un ejemplo de eso.

Si dejamos de lado otros idiomas:

  • La semántica actual de ? extiende plausiblemente a los operadores propuestos.

  • Si ve valor en los operadores _relacionados_ que se proponen - remojo nulo ( ?. ), coalescente nulo ( ?? ) y asignación condicional nulo ( ?= ) - entonces opte para una forma ternaria detallada como -then / -else no es una opción, si desea que todos estos operadores relacionados reflejen una similitud (que obviamente tienen conceptualmente).

Cuanto más exótica es una característica, más verbosidad es importante.

Cuanto más utilizada sea una característica, más concisión es importante. Y la abstracción de una representación basada en símbolos deja de ser un problema debido a la exposición repetida y pura a la sintaxis, al igual que con * , por ejemplo.

Todos los operadores que se me comentan pertenecen a la última categoría.


@RichardSiddaway :

Mis comentarios sobre $ psitem se basaron en mi experiencia personal. Si ha tenido una experiencia diferente, no invalida mi experiencia.

Sí, sus comentarios se basaron en la experiencia _personal_.
Los míos se basaron en _analizar datos_ del popular sitio de preguntas y respuestas Stack Overflow, para inferir patrones de uso _general_ (dentro de las limitaciones indicadas), lo cual no está relacionado con mi experiencia personal.

La única razón por la que podría percibir que mis comentarios invalidan los suyos es si cree que sus observaciones personales reflejan una verdad "transpersonal", una afirmación que no hizo como tal en sus comentarios. ¿Querías hacerlo? Si es así, necesitamos discutir _eso_.

Casi todos esos operadores son operadores matemáticos con un significado relativamente claro, @ mklement0 😄

Un operador ternario es un operador condicional , y _todos_ los operadores booleanos / condicionales de PS son de la forma más detallada: -and , -or , -eq , -ne , -contains , etc.

Sin embargo, estoy de acuerdo en que esta abreviatura puede tener sentido debido a la necesidad de las funciones circundantes y los operadores relacionados. Pero sí creo que la sintaxis ternaria "estándar" no es particularmente intuitiva para aquellos de nosotros que no hemos sido expuestos repetidamente a ella.

los operadores son operadores matemáticos

Entre los enumerados, solo + - * / % tienen un significado (puramente) matemático, pero el aspecto claramente entendido también se aplica a los demás (con la excepción de = , dado que a menudo se confunde con pruebas de igualdad ).

La mejor construcción con la que comparar <condition> ? <if-true> : <else> es if _statement_, no otros operadores. Si bien if es definitivamente más detallado, es precisamente ese aspecto el que la operación ternaria debe abordar (además de ser una expresión componible verdadera, a diferencia de if ).

Existe un espectro de concisión, seguro, pero, como usted dice, para acomodar todos los operadores relacionados que se proponen de manera consistente, una sintaxis basada en símbolos tiene sentido.

para aquellos de nosotros que aún no hemos estado expuestos repetidamente a él.

Bueno, es de esperar que eso cambie pronto. 😁
Punto tomado, pero (a) la sintaxis se explica fácilmente y tiene la misma complejidad conceptual que una declaración if , y (b) la exposición repetida debería ayudar con la retención de la memoria.

@ mklement0 ¿Cómo sugiere abordar ? como un carácter de nombre válido? ¿Rompiendo el cambio? Considero que las personas en el núcleo de PowerShell están bien versados ​​en PowerShell tal como está y que la sintaxis adicional (que ha existido en otros idiomas durante casi 50 años) no será un obstáculo. Siempre pueden usar if/else si quieren más verbosidad.

? es solo un alias válido en el modo de comando ; en todas las variantes del modo de expresión es simplemente un carácter inválido en la actualidad. No hay colisión.

Si intenta ingresar este código, simplemente saldrá un error:

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

Resultado:

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

@ vexx32

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

En su ejemplo de remojo nulo: $var?.maybenull() no le importa que haya un signo de interrogación allí y si alguien está tratando de condensarse demasiado, su ternario se romperá.

Lo siento, eso se estaba discutiendo principalmente en el otro tema sobre eso, así que no pensé que se estuviera refiriendo a eso.

Si podemos o no excluir que sea un carácter de nombre de variable válido depende del equipo de PS, pero me inclino a ser de la opinión de que evitar que se considere un carácter de nombre de variable por defecto no se rompería mucho. No creo que haya visto a nadie usar ? como parte de un nombre de variable.

@ vexx32 Sí, debería mencionar eso. Esto podría tener impactos adicionales si no se tiene cuidado con el alcance (aunque esto ya se ve en las expansiones de cadenas, por lo que la gente debería estar algo familiarizada con él):

$var = $test?$thing1:$thing2

pero puede que me esté partiendo demasiado los pelos de punta para aquellos de nosotros que vivimos en el caparazón.

Corregido:

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

@ mklement0 - No necesariamente estoy de acuerdo con:

La mejor construcción para comparar?:to es la sentencia if, no otros operadores. Si bien if es definitivamente más detallado, es precisamente ese aspecto el que la operación ternaria debe abordar (además de ser una expresión verdadera y componible, a diferencia de if).

Específicamente, el operador ternario existe porque C / C # son lenguajes orientados a declaraciones pero necesitan expresiones condicionales.

En los lenguajes orientados a expresiones (por ejemplo, F # o Rust), no existe una sintaxis concisa ya que se considera innecesaria. Creo que esta vieja discusión sobre la eliminación de Rust del operador ternario es interesante.

Una cosa que realmente me gusta de Rust es el uso del operador ? para el manejo de errores. No tengo una propuesta concreta para usar ? en PowerShell, pero parece que ? podría usarse mejor para el manejo de errores que para una expresión condicional.

@ TheIncorrigible1 , @ vexx32 : Sí, el remojo de nulos técnicamente sería un cambio importante, pero con suerte de tipo cubo 3 (de hecho, continuemos la discusión allí); para la operación ternaria, el uso sugerido de {...} / espacio en blanco antes de ? para la desambiguación parece resolver ese problema.

@lzybkr :

Específicamente, el operador ternario existe porque C / C # son lenguajes orientados a declaraciones pero necesitan expresiones condicionales.

Bueno, en PowerShell las declaraciones de control de flujo como if son _half_-expresiones; en expresiones _simple_, la operación ternaria propuesta sería equivalente; en los anidados, no lo haría:

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

La necesidad de $() / @() es más que un inconveniente de sintaxis: tiene implicaciones de comportamiento y rendimiento.

Dicho esto, _ deseo_ que declaraciones como if y foreach expresiones de buena fe (dos ejemplos más de cosas que actualmente fallan: foreach ($i in 1..5) { $i } | Write-Output o foreach ($i in 1..5) { $i } > out.txt ).
Sin embargo, no sé lo suficiente como para juzgar si _no pueden ser_ y / o si existe un problema de compatibilidad con versiones anteriores.
Véase también: # 6817


Si if se convirtiera en una expresión completa en PowerShell, entonces podría hacer el argumento que llevó a la eliminación del condicional ternario de Rust: entonces ya no es _necesario_.

Sin embargo, mi motivación para esta propuesta nunca fue _necesidad_ - se trata de concisión, conveniencia y legibilidad (desorden visual).


¿No tengo una propuesta concreta para utilizar? en PowerShell, pero se siente como? podría usarse mejor para el manejo de errores que para una expresión condicional.

Creo que introducir ? con una semántica fundamentalmente diferente a la de C # sería una fuente de confusión eterna.

Por separado, vale la pena discutir las mejoras en el manejo de errores de PowerShell.

Si buscamos una alternativa concisa pero poco intuitiva a If / Then / Else, ya tenemos una.

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

Y funciona en expresiones.

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

@TimCurwick : Eso es conciso (y más oscuro), pero no equivalente: el condicional ternario propuesto sería _short-circuiting_ (como una declaración if ), mientras que su sintaxis evalúa invariablemente _ambas_ alternativas.

Dicho esto, su sintaxis es sin duda la mejor opción disponible actualmente, asumiendo que uno es consciente de la limitación indicada.

Con respecto a la discusión sobre cómo mostrar opciones ternarias en PowerShell, ¿alguien ha considerado una opción en el mismo formato que usa -replace / .replace() ?

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

o

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

Esto dejaría en claro que el operador está realizando una acción ternaria llamándola literalmente ternaria . Es detallado, pero aún breve de escribir, y hace uso del comportamiento común existente de -operator $first,$second , por lo que debería resultar familiar para los usuarios de PowerShell en todos los rangos de experiencia.

🤔 podría funcionar, pero sería más incómodo que cualquiera de las alternativas propuestas. -replace funciona de esa manera porque solo acepta una matriz real de argumentos. .Replace() no es administrado por el equipo de PS - es un método en la clase .NET System.String .

Si intentáramos usar cualquiera de esas sintaxis, significaría un método ETS (que está bien, pero tiende a agregar un poco de sobrecarga de rendimiento a la creación de objetos a los que debe adjuntarse) o, con la versión del operador propones, no podríamos tener fácilmente una matriz como argumento.

Sin una carcasa especial de este tipo en el analizador sintáctico, no podríamos provocar un cortocircuito. Las sintaxis ternarias en otros idiomas generalmente existen porque _no desea_ evaluar ambas opciones; el tiempo de cálculo es más rápido si solo se necesita evaluar la rama correcta, en lugar de tener que evaluar por completo ambas opciones (lo que puede tener algunos efectos secundarios importantes).

Y dado que eso ya requeriría mayúsculas y minúsculas especiales, sería más efectivo introducir una nueva sintaxis para minimizar la confusión (sería un poco engañoso tener algo que parece una matriz pero no se puede usar como tal; no apoyaría la creación de la "matriz" con anticipación y pasarla como una variable, por ejemplo). El hecho de que los argumentos del método ya estén un poco en conflicto con la sintaxis de la matriz a menudo ya es engañoso. No creo que me gustaría agregar un comportamiento de variante _tercero_ para las comas a la mezcla.

@ PowerShell / powershell-Committee discutió esto extensamente, no todos estamos de acuerdo, pero la mayoría está de acuerdo en que es valioso tener este operador y alinearse con la sintaxis de C # manteniendo ?: ya que la expectativa es que la mayor parte del uso lo hará ser de desarrolladores de C #. Esta función será experimental a la espera de comentarios reales sobre el uso.

@ SteveL-MSFT ¿Eso significa que la función está avanzando para la versión 7.0? ¿Romperá la compatibilidad en las variables al poder usar ? en su símbolo?

@ TheIncorrigible1 sí, esta función está avanzando en PS7. No debe romper la compatibilidad con el uso de ? alias. Existe una preocupación sobre la agudeza visual de ? cuando se mira un guión que intenta diferenciar Where-Object y ternary , pero veremos qué comentarios de los usuarios al respecto. En general, no esperamos que la mayoría de los usuarios utilicen este operador, pero eso no debería impedir que avance.

@ SteveL-MSFT Me refiero a variables con un nombre de $isValid? o similar. Estos son tokens válidos en la iteración actual de PS.

@ TheIncorrigible1 :

Requerir espacios en blanco entre el primer operando y ? resuelve ese problema, como se sugirió anteriormente, y para mí es una solución perfectamente razonable:

  • El : _también_ requiere un espacio en blanco alrededor, porque algo como $true ? $number:42 no funcionaría, dado que $number:42 _como un todo_ se interpretaría como una referencia de variable única.

  • Si bien C # _permite_ true?number:42 , no creo que debamos (o, de hecho, podamos) preocuparnos por la compatibilidad en ese nivel. Personalmente valoro la concisión, pero no a expensas de la legibilidad; incluso si pudiera escribir $true?$number:42 , no lo haría.

(La compatibilidad con versiones anteriores será un problema cuando (pista, pista) implementemos el acceso condicional nulo . La permisividad de PowerShell con respecto a los nombres de los identificadores es generalmente problemática, como @KirkMunro ha argumentado recientemente, pero ese barco ha zarpado )

Sí, creo que dejar el requisito de espacios en blanco es sensato. Después de todo, ya es bastante conciso. 😁

El prototipo se esforzó bastante en analizar los números con ? y : en ellos de manera diferente en el contexto del operador ternario (donde sabemos que estamos esperando una expresión). Entonces puedes escribir cosas como ${isWindows}?12:47 .
Números como 123? o 1:23 se tokenizan como un token genérico hoy, lo que no es útil en absoluto en el caso en el que sabemos que estamos esperando una expresión.

Para las variables, no hay ningún cambio en la forma en que ? o : se pueden usar para el nombre de la variable, ya que la variable es una expresión.

Buen punto, @ daxian-dbw; Olvidé que {...} se puede usar para resolver cualquier ambigüedad de límite de nombre de variable, así que supongo que los golfistas de código podrían usar algo como ${isWindows}?${number}:47

¿Podemos cerrar esto ahora?

Cerrar por # 10367

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