Powershell: Предложение: реализовать объединение нуля, условный доступ к нулю (замачивание нуля), присвоение условного нуля

Созданный на 2 мар. 2017  ·  71Комментарии  ·  Источник: PowerShell/PowerShell

Объединение нулей и доступ с нулевым условием (поглощение нулей) были бы удобными дополнениями к языку.

_Update_: @BrucePay дополнительно предлагает _assignment_ с ?= - см. Комментарий ниже .

Например, вместо написания:

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

можно было бы написать:

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

Повторный доступ с нулевым условием: если Set-StrictMode выключено (по умолчанию), вы можете просто использовать $varThatMayBeNull.Name - специального синтаксиса не требуется; однако, если действует Set-StrictMode -Version 2 или выше, $varThatMayBeNull.Name будет _break_, и здесь полезен оператор нулевого условия ( ?. ), чтобы сигнализировать о явном намерении игнорировать $null кратко.


Открытый вопрос :

$varThatMayBeNull?[42] обрабатывает случай, когда переменная $null , но если это не так, элемент массива с указанным индексом _должен существовать_.

Поэтому было бы также полезно сделать _indexing_ null-условным - что-то, что C #, кстати, _не_ поддерживает (вы должны использовать .ElementAtOrDefault() ).

Два основных варианта:

  • Придумайте дополнительный синтаксис, который явно сигнализирует о намерении игнорировать несуществующий _index_:

    • Вопрос в том, какой синтаксис выбрать для этого, учитывая, что ?[...] и [...]? не подходят из-за двусмысленности.
    • Возможно, [...?] , но это кажется неудобным.
  • Положитесь на существующее поведение в отношении доступа к несуществующим индексам, как подразумевается настройкой Set-StrictMode - см. Таблицу ниже .


Связано: реализовать тернарные условные выражения

Issue-Enhancement Resolution-Fixed WG-Language

Самый полезный комментарий

@rjmholt я сделал анализ здесь . Краткая разбивка: из почти 400 000 скриптов с 22 000 000+ именами переменных (не уникальных) было только ~ 70 уникальных переменных, оканчивающихся на ? .

Все 71 Комментарий

@ mklement0 Кажется, второй образец работает по дизайну без "?".
Может поменять на name() ?

@iSazonov : Хороший замечание, но он работает только без ? если Set-StrictMode -Version 2 или выше не _не_ в силе - я обновил исходный пост, чтобы прояснить это.

Я думаю, что синтаксический сахар - это то, что Powershell может использовать, что нравится другим языкам. +1 к предложению.

Рассмотрим следующие примеры из других языков:

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

четный

a = b if b else c

Это лучше чем

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

и часто бывает необходимо уточнить с помощью дополнительно подробных

a = (если (b -ne $ null) {b} else {c})

Заставляет чувствовать себя грязным и разбитым.

Я обнаружил, что делаю это сегодня как обходной путь.

`` PowerShell
$ word = ($ null, «два», «три»). Где ({$ _ -ne $ null}, «Первый»)
`` ''

Я использую похожую схему:

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

@kfsone В вашем примере есть небольшая ошибка $a=(if ($b -ne $null) { $b } else { $c }) . Это должно быть $a=$(if ($b -ne $null) { $b } else { $c }) однако единственной версией PowerShell, в которой требуется $( ) была версия 1. Начиная с версии 2, вы можете просто сделать:

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

@bgshacklett Разве вы не имеете в виду $word=($null,'two')[$null -ne 'three'] ?

Немного жаль, что теперь с 6.1 до 6.2 перешли в «Будущее».

@ TheIncorrigible1 Нет, если вы скопируете и $word установлено на "два". Более подробная информация содержится в ответе на вопрос о переполнении стека, где я впервые увидел шаблон:
https://stackoverflow.com/a/17647824/180813

В то время как perlesque hack-around обращается ко мне 20 лет назад, который написал shebang, который зарегистрировал и / или запросил запись пользователя или организации RIPE-DB, я надеюсь на то, что PowerShell побуждает моих коллег использовать язык вместо того, чтобы вселять в них страх.

Моя лакмусовая бумажка такова: хочу ли я прочитать это на своем планшете в 3 часа утра новогоднего утра, когда генеральный директор по телефону кричит мне, сколько миллионов долларов мы теряем за секунду.

(Кроме того: это было лишь незначительным преувеличением реального опыта, пока я не работал в Facebook и не вернулся после срочной быстрой утечки информации, чтобы мне сказали, что за 2 минуты моего отсутствия больше людей, чем население Голландии, получили пустой Лента новостей. Это был не мой код, и ошибка заключалась в незначительном изменении семантики return x vs return (x) в стандарте C ++ для очень специфических случаев шаблона, и «не хотите ли вы прочитать этот код за 2 минуты?» дедлайн, полный мочевой пузырь и судьба каждого сабо с изображением кота голландца на плече ??? "звучало не так круто)

Ага. В PS есть несколько хитростей, которые отлично подходят в крайнем случае или если вам нужно одноразовое сокращение.

Для поддерживаемого кода в идеале мы должны иметь явные операторы объединения с нулем, такие как C #. Основная проблема для меня в том, что мы для этого используем? ? уже имеет псевдоним Where-Object (как бы мне ни хотелось, чтобы это было стерто, оно очень часто используется). Имейте в виду, что % имеет псевдоним ForEach-Object но это не препятствует операциям модуля, поэтому теоретически, по крайней мере, наличие ? как оператора объединения с нулем также потенциально может хорошо; он будет интерпретироваться как таковой только в выражениях, где Where-Object любом случае недействителен.

@ vexx32 :

По крайней мере, _syntactically_ ?? должно подойти, потому что мы говорим о режиме _expression_, тогда как ? , как команда [псевдоним], распознается только в режиме _argument_.
Не уверен, что повторное использование символа вызывает путаницу, но это не первый случай, когда символ выполняет двойную функцию в разных контекстах.

Удивительно, но использование ?. и ?[] для замачивания нуля технически было бы критическим изменением, поскольку PowerShell в настоящее время допускает ? в качестве не начального символа в имени переменной.

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

Тем не менее, я надеюсь, что это будет считаться изменением « Ведро 3: маловероятно серая область» .

Я не могу сказать, что когда- нибудь видел, чтобы кто-нибудь использовал? в имени переменной ... Я бы тоже не стал, потому что есть вероятность, что это будет неправильно прочитано. Но да, надеюсь, это должно быть идеально использовано.

Я подозреваю, что уже немного поздно поднимать этот вопрос, но Bash справился с этим (и некоторыми другими случаями) с помощью своих функций замены параметров: https://www.tldp.org/LDP/abs/html/parameter-substitution.html.

Несмотря на то, что это может быть медведь, которому нужно научиться из-за огромного количества вещей, которые можно сделать с его помощью, он невероятно мощный. Я понимаю, что было бы невозможно использовать эту точную нотацию из-за того, как PowerShell использует фигурные скобки с переменными, и это не обязательно будет соответствовать общему ощущению языка, но похоже на полезную точку данных.

@bgshacklett :

Да, подстановка параметров - это мощное средство, но, к сожалению, это не только "учиться", но и "помнить".

Таким образом, хотя _функции_ Bash часто интересны, их _синтаксическая форма_ часто является загадочной, трудно запоминающейся и не очень подходящей для PowerShell.

_Brace extension_ (например, a{1,2,3} в bash расширяется до a1 a2 a3 ) - это пример интересной функции, выразительность которой я бы хотел видеть в PowerShell, но с подходящей для PowerShell синтаксис - см. # 4286

Я полностью согласен. Я привел это скорее как пример того, как эта проблема была решена где-то еще, чем как точное решение.

Можно рассмотреть еще один оператор:

$x ?= 12

который установит $x если он не установлен (не существует). Это часть «шаблона инициализатора», который не распространен в обычных языках, но для языков (с динамической областью видимости), таких как оболочки, инструменты создания и т. Д., Довольно часто бывает сценарий, который устанавливает значение по умолчанию, если пользователь его не указал. . (Хотя на самом деле инициализаторы параметров довольно распространены.)

Распространение этого на свойства:

$obj.SomeProperty ?= 13

добавит и инициализирует свойство заметки SomeProperty для объекта, если оно не существует.

И - для удовольствия - еще один вариант инициализации переменной с помощью -or :

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

$x ?= 12 звучит как отличная идея.

Мне пришло в голову, что нам, вероятно, следует применить все эти операторы не только в том случае, если LHS не _существует_, но и если он _ существует, но случайно содержит_ $null[System.Management.Automation.Internal.AutomationNull]::Value рассматриваемым как $null в данном контексте).

добавить и инициализировать свойство заметки SomeProperty

В этом ключе $obj.SomeProperty ?= 13 имеет смысл для меня _ только_, если .SomeProperty существует и содержит $null , учитывая, что вы не можете неявно создавать свойства даже с обычными назначениями (для сравнения, для _hasthables_ неявное создание записи имеет смысл).

Все обсуждаемые операторы должны будут освободить LHS от проверки существования в строгом режиме.

Мне интересно, почему strictmode не позволяет вам получить доступ к несуществующему свойству. Есть ли намерение отловить опечатки вроде $x.pretnd ? Есть ли намерение проверить предположения типа assert(x != null) ? Есть ли намерение заблокировать случайное распространение $null дальше в вашем коде?

замачивание нуля (?.) полезно, чтобы кратко сигнализировать о явном намерении игнорировать $ null.

Разве это не то, что . сигнализирует уже в нестрогом режиме? Если бы вы хотели быть строгими, вы могли бы сначала проверить наличие .Name , не проверяя сначала, вы уже обозначили явное намерение, что проверка не важна для вас.

Если StrictMode имеет цель, при которой доступ к несуществующему свойству и возвращение $null запрещены, то не будет та же аргументация применима к ?. , и это должно вызывать то же исключение по той же причине . Если нет, то почему?

С помощью объединения с нулевым значением вы можете написать:

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

Быстро ли станет рекомендованным или идиоматическим всегда использовать ?. для каждой ссылки на свойство, потому что он «ведет себя так же, как . , и не будет вызывать исключения для людей, использующих строгий режим»?

Есть ли реальное желание иметь настраиваемый строгий режим с настройками переменных, чтобы, например, вы могли иметь объявление в верхней части сценария # StrictMode SkipMemberExistenceCheck или атрибут escape-штриховки для указания блока unstrict code в общем-то? [Я подозреваю, что желанием является сжатый синтаксис в стиле C #, но вы понимаете, о чем я]

Спасибо за мысли, @HumanEquivalentUnit.

Есть ли намерение отловить опечатки вроде $x.pretnd ?

Я не могу говорить о замысле дизайна, но это то, что имеет для меня смысл - аналогично тому, что Set-StrictMode -Version 1 делает для _variables_ (только).

В случае переменных речь идет об их _существовании_, а не о том, окажется ли значение $null , и проверка существования свойства следует тому же шаблону.

Я думаю об этом как о наиболее близком к динамическому языку сценариев способу поиска ошибок, о которых статически типизированный скомпилированный язык сообщит во время _компиляции_.


Разве это не то. сигналы уже в нестрогом режиме? Если бы вы хотели быть строгими, вы могли бы сначала проверить наличие .Name

Да, но в нестрогом режиме вы отказываетесь от вышеупомянутых проверок существования, а тестирование вручную, очевидно, довольно громоздко и неизменно медленнее, чем встроенная функция.

не проверяя сначала, вы уже выразили явное намерение, что проверка не важна для вас.

Дело в том, что с Set-StrictMode -Version 2 или выше вы получаете:

  • преимущество проверки существования члена _по умолчанию_
  • возможность отказа _по запросу, кратко_ с помощью .?

у вас может быть объявление в верхней части сценария # StrictMode SkipMemberExistenceCheck или атрибут escape-штриховки для указания блока unstrict code целом

Связано: текущая динамическая область видимости Set-StrictMode проблематична; см. проект RFC https://github.com/PowerShell/PowerShell-RFC/blob/master/1-Draft/RFC0003-Lexical-Strict-Mode.md

преимущество проверки существования члена по умолчанию

PS содержит код, который выполняет проверку членов и возвращает $ null, если они не существуют. Это преимущество по умолчанию, которого вы также можете избежать, написав собственный тест на существование участника с $x.psobject.properties... если захотите. StrictMode лишает этого преимущества и оставляет затруднения, связанные с написанием тестов существования. Тогда вместо того, чтобы дать хороший способ написать точный тест на существование члена, ?. предоставит вам краткий обходной путь, чтобы получить то, что всегда делал . . И если важно, что член существует, вам все равно придется кодировать его отдельно.

Но это заставляет меня спросить, а как насчет вызовов методов:

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

т.е. ?. будет вести себя так же, как . для поиска свойств в нестрогом режиме, но будет вести себя иначе, чем . для вызовов методов в нестрогом режиме, делая его нюансированным, а не Прямая замена. Означает ли это, что при использовании ?. вас вообще не будет возможности узнать, был ли вызван метод, или вообще ничего не произошло? Свойства могут поддерживаться методами получения, но я думаю, что в DotNet есть соглашение о том, что геттеры не изменяют внутреннее состояние, но нормально для вызовов методов для изменения состояния. С ?. вы бы не знали, изменили ли вы состояние объекта?

Интересно, можете ли вы получить желаемые преимущества, и даже лучше, сделав ?? способным обрабатывать исключения PropertyNotFoundException и MethodNotFound напрямую из выражения слева (но не других исключений, возникающих внутри методов), а также обработки $ нули и вообще не имеют ?. . например

$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

И тогда вместо ?. вызова члена или доступа к свойству это может быть краткий способ спросить, существует ли член, возвращая [bool].

С тем же добавлением синтаксиса ?? и ?. вы можете обрабатывать больше ситуаций с меньшим запутанным перекрытием.

StrictMode лишает этого преимущества и избавляет от необходимости писать тесты существования.

Помеха для одного человека - польза для другого:
Все зависит от того, чего вы хотите _по умолчанию_:

  • Если вы уверены, что в вашем коде нет _typos_ - обязательно воспользуйтесь поведением _default_ (строгий режим ВЫКЛЮЧЕН) - и вам не понадобится .? (для доступа к _property_ см. следующий комментарий повторно _метод вызовов_ и _индексирование_).

    • О _персональном_ примечании: я обычно использую Set-StrictMode -Version 1 чтобы избежать опечаток в _variable_ именах, но считаю -Version 2 или выше слишком раздражающим, в первую очередь из-за # 2798 (это ошибка, не это предложение).
  • Если вы хотите убедиться, что вы (а) не ошиблись в написании имен свойств и / или (б) ваш код случайно не работает с типами данных, отличными от тех, с которыми вы собирались работать, установите для строгого режима версию 2 или выше. .

    • В самом деле, это _в настоящее время_ затрудняет _отключение_ этих проверок _по требованию_,
    • именно поэтому здесь предлагается ввести нулевой условный доступ: сделать _легким_ отказ по запросу.

Явное тестирование на наличие члена - это действительно отдельный вариант использования, который может быть необходимостью независимо от действующего строгого режима.

Что касается _method calls_, которые OP не покрывает:

_Method calls_ (например, $varThatMayBeNull.Method() ) и _indexing_ (например, $varThatMayBeNull[$index] ) - это два случая, когда даже отключенный строгий режим или версия 1 может принести пользу, учитывая, что оба случая в настоящее время _ неизменно_ вызывают ошибку, если доступ к значению $null .

Синтаксис будет таким же, как для свойств для методов - $varThatMayBeNull?.Method() - и аналогичным для индексации - $varThatMayBeNull?[$index] - как в C #.

_Update_: есть второй аспект индексации, а именно, если переменная не равна нулю, но элемент по данному индексу не существует (например, $arr = 0,1; $arr[2] ). В строгом режиме версии 2 или ниже это оценивается как $null , но в версии 3 или выше это вызывает ошибку, и было бы неплохо иметь возможность отказаться от этой ошибки. Однако синтаксис для этого случая представляет собой проблему - см. Обновленный OP, который в настоящее время предлагает, возможно, неудобный [...?] .

И да, я бы сделал такой доступ по умолчанию для $null , даже для методов - опять же, вы _неявно_ сигнализируете, что ничего не делать нормально, если доступ к объекту $null или если такого элемента массива не существует.

Обратите внимание, что C # не имеет нулевого условного индексирования во втором смысле.

Он имеет нулевое условное индексирование, что не совсем похоже на то, что вы предлагаете. C # позволяет (я почти уверен, по крайней мере ...) array?[0] который обходит обычную проблему «индекс в нулевой массив / коллекцию» и просто возвращает null.

Но да, я согласен, что это хорошая идея. Это избавляет нас от обработки исключений и сохраняет код довольно ясным и лаконичным.

@ vexx32 , это _один_ аспект условного индексирования с нулевым значением: если array в array?[0] равно null , операция индексирования игнорируется - в C # это тоже есть, как вы указываете.

Я (обновление: _также_) говорил о _другом_ аспекте условного индексирования с нулевым значением: случай, когда array в array?[0] _не_ null но это _элемент с индексом 0 _, которого не существует.

Насколько мне известно, последнее нельзя игнорировать в C #, но я думаю, что это тоже было бы полезно.

Можете ли вы придумать терминологию, чтобы дать этим двум аспектам разные названия?

Код из другой проблемы JavaScript изменится с $_.Description[0].Text на $_?.Description[0?]?.Text что я считаю некрасивым; и мое другое предложение о том, как ?? может вести себя, приведет к $_.Description[0].Text ?? что субъективно лучше, и будет - если возможно реализовать - обработать сбои в любой точке поиска в цепочке за один раз , и по-прежнему позволяете вам выбирать, что вы хотите сделать по умолчанию, и иметь другой запасной вариант по желанию вместо того, чтобы ограничиваться только $null .

Кроме того, будет ли этот синтаксис ?. иметь аналог для статических свойств и методов, например $t = [int]; $t::MaxValu; $t::Pars("1") , станет ли это ?: или ?:: ?

Каким будет желаемое поведение при индексировании массива с указанием более чем одного индекса? $array[0,4?,1,2] где каждый может потерпеть неудачу, или $array[0,4,1,2?] где только весь участок может быть успешным или неудачным?

Сначала мне нужно сделать шаг назад, потому что я понимаю, что я объединил аспекты, которые стоит разделить, по крайней мере, концептуально:

  • _Null-value_-условный доступ к члену или индексу, как в C #:

    • Если значение, к которому осуществляется доступ, - $null , игнорируйте попытки доступа к его членам или индексации в нем и оценивайте как $null .
  • _Member-exist_-conditional доступ к члену или индексу, специфичный для PowerShell:

    • Если используется значение _non- $null _, игнорируйте попытки доступа к несуществующим _members_ (свойства, вызовы методов, индексация), которые не существуют.

Примечание. Для краткости здесь я использую _member_ несколько вольно, чтобы также охватить _elements_ объектов, которые оказались коллекциями, доступ к которым осуществляется с помощью _indexing_, а не точечной нотации.

Если вы уверены, что в вашем коде нет опечаток - во что бы то ни стало, воспользуйтесь поведением по умолчанию (строгий режим ВЫКЛЮЧЕН) - и вам не понадобится.? (для доступа к собственности

@ mklement0 Я думаю, вы обсуждаете с точки зрения « один человек использует строгий режим для улучшения своего кода », а я - с точки зрения « кто-то другой может запустить мой код в строгом режиме, какие изменения заставят мой код работать и для них? "и это приводит меня к различным рассуждениям. С ?. было бы настолько удобно использовать его вместо . и заставить код также работать в строгом режиме, что я могу использовать его везде, как обычно; Я ничего не теряю и обретаю совместимость. Я боюсь, что весь код PowerShell будет таким образом искажен, потому что он «работает» в большинстве случаев.

Но это не прямая замена, потому что она заглушает неудачный поиск вызова метода в нестрогом режиме и заглушает неудачный поиск свойств в строгом режиме - это добавляет неудобный нюанс к поиску членов, невероятно распространенной операции. Это не поможет никому, кто хочет получить выгоду от проверок в строгом режиме, упрощая этот шаблон. Он не помогает достаточному количеству людей в достаточном количестве ситуаций, поскольку добавляет сложности. И это слишком удобно, чтобы сделать код более совместимым, я не думаю, что «игнорируйте это, если вы этого не хотите» достаточно сильно, чтобы сдерживать его.

PowerShell может делать то, что не делает C #, например, устанавливать автоматические переменные или иметь прецедент, когда исключения генерируются и заглушаются за кулисами. Должен быть лучший подход, который совсем не усложняет поиск участников, но упрощает шаблон строгой проверки безопасности, чтобы людям, которые действительно хотят использовать проверки, было легче, а людям, которых раздражали проверки, тоже было легче.

@HumanEquivalentUnit Как заставить эти вещи замолчать? Вместо этого вам придется заранее написать загрузку обработки исключений и нулевых проверок:

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

v.

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

И этот случай не редкость. Или вы просто бросаете $ErrorActionPreference = 'Stop' и оборачиваете все это в try/catch чтобы упростить нулевую проверку, что является плохим шаблоном (логика, управляемая исключениями).

Кроме того, это будущее языка, мы не вернемся к 5.1 и что-то изменим. Если вам нужно больше последователей, вам нужно упростить чтение кода, что, как мне кажется, делает это предложение.

@ mklement0 Я думаю, вы обсуждаете с точки зрения «_один человек, использующий строгий режим для улучшения своего кода_», а я с точки зрения «_кто-то еще может запускать мой код в строгом режиме, какие изменения заставят мой код работать и для них? _ "

Мы говорим об эквиваленте "set -euo pipefail" (строгий режим bash)?

a- Ограничение поиском переменных (хотя я не понимаю, почему вы думаете, что простая проверка на ноль при поиске членов будет плохой вещью, фактический поиск членов намного дороже, чем if (result is null) )
b- Используйте [Strict] в областях / кодовых блоках, чтобы синтаксический анализатор обрабатывал их как таковые,
c- Строгость зависит от области действия: код, не отмеченный строгим, не является строгим.

Если я написал строгий код, который не работает при его использовании, значит, один из нас совершил ошибку. Либо я сослался на отсутствующую переменную в коде, который никогда не тестировал, либо вы неправильно поняли мой плохо спроектированный API, который зависит от существования переменных, которые не передаются в мою функцию, и вы не смогли заполнить переменную, которую я ожидаю заполнить. .

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

Функция «Журнал» не была отмечена строгой, поэтому на опечатку не жалуется.

🤔 Теперь, когда вы упомянули об этом, атрибут [Strict()] был бы _ удивительным_ способом реализовать строгий режим с ограничением области действия. Это нужно упомянуть в той другой ветке, посвященной проблемам строгого режима, я найду это и сделаю ссылку здесь ...

@ TheIncorrigible1 « Как это заглушить эти вещи? » В нестрогом режиме $null.x молчит, $null.x() является исключением. С ?. как обсуждалось, $null?.x молчит, $null?.x() молчит.

Таким образом, у вас будет . который работает как ?. в C #, за исключением строгого режима, когда он выдает исключения. Тогда вы бы иметь ?. , который работает в строгом режиме , как C # 's ?. и , как PowerShell - х . работает в в нестрогой режиме, но работает по- разному в PowerShell - х . в нестрогом режиме для вызовов методов. Какая ужасная комбинация (и комбинация, в которой ?. явно лучше и полезнее во многих из этих сценариев).

Вместо этого вам придется заранее написать загрузку обработки исключений и нулевых проверок: $prop = $item?.Method().PropIwant ?? 'PropActionFailed'

Вызов вашего метода может вызывать или возвращать $ null, а PropIWant может отсутствовать, вам все равно придется написать:

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

vs с предложенным мной ?? (если это возможно построить), и нет необходимости в ?. , и он охватывает возможные случаи исключений метода в случае, если все, что вас волнует, это "успех или нет" и никакой подробной обработки ошибок.

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

Если вам нужно больше последователей, вам нужно упростить чтение кода, что, как мне кажется, делает это предложение.

Как часто вы вводите . в PowerShell? Как часто вы хотите объяснять новым пользователям, в чем разница между . и ?. и говорить им, что они должны учитывать разницу каждый раз, когда они навсегда напечатают . ?

"О, как это произошло?" «Ну, в C # . выдавало исключение для отсутствующих членов, поэтому они изобрели ?. которого не было. Это было здорово, поэтому они сделали это в PowerShell по умолчанию, . не бросает. Затем они изобрели строгий режим, который заставляет . вести себя как C # и бросать, но только в этом контексте, но способ проверки элементов вручную был действительно многословным и утомительным, и никто не хотел его вводить; вместо того, чтобы напрямую решить эту проблему и сделать ее более удобной для использования в строгом режиме, они уклонились от этого и подражали C # ?. вместо этого, чтобы получить скрытый способ избежать строгости, которую вы просили, что в некоторой степени удобно для вас, но отстой для всех остальных. И у вас до сих пор нет теста на существование участников, и использование strictmode по-прежнему многословно и утомительно, но, по крайней мере, вам не нужно страдать от этого, потому что у 'strictmode' есть аварийный люк 'normalmode' в настоящее время". Ик.

Если я написал строгий код, который не работает при его использовании, значит, один из нас совершил ошибку.

хотя я не понимаю, почему вы думаете, что простая проверка на null при поиске членов будет плохой вещью, фактический поиск членов намного дороже, чем if (результат равен null)

Я не думаю, что это было бы плохо, PS non-strictmode уже делает это, и я думаю, что это было бы желательной альтернативой предложенному ?. - совсем другое, полезное в большем количестве ситуаций.

Но обратите внимание, что в PS вы можете делать то, что не может C #:

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

и никаких исключений в нестрогом режиме. Измените числа и посмотрите, сколько времени это займет; судя по производительности и тому, как я думаю, это должно работать за кулисами для индексации произвольных объектов, кажется, что для нашего удобства на самом деле вызывается и заглушается ~ 100000 исключений. PS не всегда делает выбор «должно быть как можно быстрее, создавайте неудобства для пользователя», и мне это нравится.

@HumanEquivalentUnit На каждом языке есть множество функций, которые вы никогда не сможете использовать в своей карьере, и если вам не нравится стиль, ничего страшного, вам не нужно использовать эти функции. Я не понимаю, почему вы пишете строгий режим; это хорошая практика в сценариях, поэтому вы сознательно имеете дело с проблемами, а не позволяете языку поглощать их (и, по сути, иметь неявные пустые блоки catch везде). Опять же, вы по-прежнему можете не использовать эти функции (например, я никогда не использовал Out-Default ).

Кроме того, это оператор ? , а не ?. ; он также будет работать с доступом к индексу.

Чтобы продолжить закладку основы для дальнейшего обсуждения, позвольте мне резюмировать, как существующие строгие режимы влияют на условный доступ с нулевым значением и условный доступ к выше ):

Столбцы ниже представляют настройки Set-StrictMode , а значения столбцов указывают:

  • 👍 ... разрешено
  • 🚫 ... запрещено (вызывает ошибку завершения оператора)

В стороне: тот факт, что ошибки являются только _statement-_, а не _script_-terminating, относится к более широкому обсуждению обработки ошибок PowerShell - см. Https://github.com/PowerShell/PowerShell-Docs/issues/1583.

  • _Условный доступ с нулевым значением - $obj _itself_ is $null :

Построить | -Off | -Версия 1 | -Версия 2 | -Версия 3+
---------- | ---- | ---------- | ---------- | ------------
$ obj | 👍 | 🚫 | 🚫 | 🚫
$ obj.Prop | 👍 | 👍 | 🚫 | 🚫
$ obj [42] | 🚫 | 🚫 | 🚫 | 🚫
$ obj.Method () | 🚫 | 🚫 | 🚫 | 🚫

Любопытно, что с -Off и -Version 1 , $obj.Prop разрешено, а $obj[42] - нет.

  • _Member-exist_-conditional доступ - $obj не $null , но член / элемент, к которому осуществляется доступ, не существует:

Построить | -Off | -Версия 1 | -Версия 2 | -Версия 3+
---------- | ---- | ---------- | ---------- | ------------
$ obj.Prop | 👍 | 👍 | 🚫 | 🚫
$ obj [42] (индексируемый) | 👍 | 👍 | 👍 | 🚫
$ obj [42] (без индексации) | 👍 | 👍 | 🚫 | 🚫
$ obj.Method () | 🚫 | 🚫 | 🚫 | 🚫

Любопытно, что по своей сути индексируемые объекты (например, массивы) разрешают доступ к несуществующим элементам даже с -Version 2 , тогда как скаляры - где PowerShell предоставляет возможности индексации для унифицированной обработки коллекций - нет.

Оператор замачивания нуля (

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

когда вы действительно _должны быть в состоянии написать:

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

Пожалуйста, ребята, если бы вы могли получить только null-conditional из этого предложения и только для свойств, это спасло бы так много людей от боли.

Я начал смотреть на это и обнаружил несколько проблем.

Давайте рассмотрим ?? и ?=

$x ?= 1 и $x ?? 1 кажутся простыми. Но, поскольку они являются операторами, нам необходимо поддерживать $x?=1 и $x??1 .

Проблема в том, что оба $x? и $x?? проверяют имена переменных в PowerShell. Единственный способ устранить неоднозначность - это ${x}?=1 и ${x}??1 .

И более того, для условного доступа к члену ?. и ?[] нам понадобятся ${x}?.name и ${x}?[0] .
Для них $x ?.name и $x ?[0] не поддерживаются.

Другой вариант - внести критическое изменение и вообще не допускать ? в имени переменной.

Что вы думаете? @ mklement0

/ cc @rjmholt @ daxian-dbw @JamesWTruher

Я никогда особо не любил и не понимал, почему ? - допустимое имя переменной. Это открывает дверь для таких имен, как $Safe? которые в любом случае более понятны и менее неудобны, если их записать как $IsSafe .

Я думаю, что это изменение, вероятно, наступило давно.

Это открывает двери для таких имен, как $ Safe? что обычно более понятно и менее неудобно, если писать как $ IsSafe

Интересно, что я выразил противоположное мнение. Это классическая традиция Scheme / Ruby .

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

Разве тернарный оператор не имел той же проблемы, когда решение заключалось в том, чтобы требовать пробелы вокруг оператора или фигурные скобки вокруг имени переменной, чтобы он правильно работал с переменными, заканчивающимися на ? ?

Я ожидал, что с введением этих операторов PowerShell будет уделять приоритетное внимание распознаванию ? как части оператора в синтаксисе, таком как $x?[0] , так что пользователи, использующие имена переменных, оканчивающиеся на ? для хранения коллекции вместо этого необходимо использовать следующий синтаксис (поскольку в этом случае пробелы будут недопустимыми): ${x?}?[0] . То же самое для $x?.Name и ${x?}?.Name .

Другой вариант - внести критическое изменение и не разрешить? в имени переменной вообще.

👍 Учитывая, что это серьезное изменение версии (с 6 по 7), я думаю, что здесь стоит сделать серьезное изменение. Я бы хотел, чтобы у GitHub был лучший поиск кода, чтобы увидеть, сколько существует экземпляров переменных PS, которые заканчиваются на ? . Я подозреваю, что это не так уж и важно, но было бы неплохо проверить это на GitHub. За 14 лет использования PowerShell я ни разу не использовал ? в имени переменной, но, возможно, это только я. :-)

Этот корабль уже давно отправился в плавание, и я не удивлюсь, если сегодня в скриптах используются переменные, оканчивающиеся на ? .

На этом этапе, если мы просто отдадим приоритет синтаксическому анализу ? как части оператора, а не как части имени переменной, когда дело доходит до этих новых операторов, людям, которые используют имена переменных, заканчивающиеся на ? , потребуются использовать {} или пробелы (где разрешены пробелы), чтобы использовать эти переменные с этими операторами.

Странно слышать в этом контексте фразу «этот корабль отплыл». Это серьезное изменение версии. Я думаю, что это не лишено смысла здесь менять.

@rkeithhill Я использовал его в личных

@KirkMunro, имеющий "приоритетный синтаксический анализ", звучит как открытая дверь для ошибок.

@ vexx32 : ? при условии, что они используют {} вложений для идентификации имени переменной.

Обратите внимание, что у вас может быть имя свойства, которое заканчивается на ? . В настоящее время, если вы попытаетесь просмотреть такое свойство в PowerShell, не заключая имя в кавычки, вы получите ошибку парсера.

Например:

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

Я немного удивлен, что сегодня не разбирается (почему этот синтаксический анализ?), Но, тем не менее, для таких свойств вам нужно заключить их имя в кавычки, и в этом случае вы можете следовать за цитатой с тернарным, null -coalescing и т. д. без пробелов, и он будет работать нормально. Я считаю этот синтаксис очень похожим на ${x?}?.name , и меня устраивает позиция, согласно которой вы можете использовать такие имена переменных / свойств, если хотите, но для таких имен может потребоваться дополнительный синтаксис или интервал для работы с тернарным или нулевым - * операторы.

@KirkMunro Ничто не мешает людям использовать границы переменных в будущем, если им нужны эзотерические имена переменных. Я согласен с другими в том, что мне интересно, как в настоящее время используется это поведение.

Люди, использующие PowerShell 7, скорее всего, уже являются энтузиастами и будут в курсе последних изменений. Люди, которые этого не делают, все еще используют <= v5.1 и будут продолжать использовать его еще долгое время; вероятно, пока msft не удалит его из Windows 10 (никогда).

@KirkMunro Конечно, но удаление его из стандартных допустимых символов переменных не мешает пользователям в любом случае просто использовать ${Valid?} качестве имени переменной. Поскольку они должны были бы делать это с этими операторами в любом случае, я думаю, было бы лучше сделать это согласованным, а не превращать ? в символ, который _ только иногда_ считается частью имени переменной.

Это уже _is_ будет переломным изменением, и я думаю, что лучше, по крайней мере, быть последовательным в этом отношении и идти до конца, а не вводить новый уровень двусмысленности. 🙂

@adityapatwardhan Я думаю, что для языка было бы лучше удалить ? как допустимый символ переменной. Он легко включил бы как null-soak / -coalesce, так и тернарные операторы в знакомом синтаксисе, что добавило бы много эргономичности процессу создания сценария.

@KirkMunro, имеющий "приоритетный синтаксический анализ", звучит как открытая дверь для ошибок.

@ TheIncorrigible1 : Любой код может открыть дверь для ошибок, если он не реализован должным образом. Я просто говорю о простом односимвольном просмотре вперед, чтобы определить, работает ли PowerShell с тернарным оператором или оператором null- *, когда он анализирует имя переменной, которое не заключено в границы переменных, и встречает символ ? . Это несложно и не открывает двери для большего количества ошибок, чем любое другое изменение кода.

Люди, использующие PowerShell 7, скорее всего, уже являются энтузиастами и будут в курсе последних изменений. Люди, которые этого не делают, все еще используют <= v5.1 и будут продолжать использовать его еще долгое время; вероятно, пока msft не удалит его из Windows 10 (никогда).

@ TheIncorrigible1 : Какие у вас есть основания / доказательства этого утверждения? PowerShell 7 находится на стадии предварительной версии, поэтому сегодня она используется только энтузиастами. Это само собой разумеющееся. Но помимо предварительной версии, если PowerShell 7 или более поздней версии предлагает привлекательные функции, которые необходимы компаниям, при поддержке необходимых им функций, они будут использовать эти версии. Это особенно верно, если PowerShell 7 устанавливается вместе с ОС. Единственное, что нужно энтузиастам, - это организации, у которых нет бизнес-потребности в том, что PowerShell 7 предлагает.

Это уже будет переломное изменение, и я думаю, что лучше, по крайней мере, быть последовательным в этом вопросе и идти до конца, а не вводить новый уровень двусмысленности. 🙂

@ vexx32 Это растягивает. Было бы критическим изменением, если бы у вас было ?? в имени переменной, но вероятность этого гораздо более мала, чем наличие переменной, имя которой оканчивается на один ? . В остальном, как могло бы быть введение операторов null- * при одновременной поддержке ? в качестве стандартных разрешенных сценариев разрыва символов переменных сегодня?

По моему опыту, ломающие изменения для того, что нужно иметь (а это, кажется, и есть), гораздо чаще, чем не отвергаются, и обсуждение / аргументы вокруг них служат только для того, чтобы замедлить процесс достижения цели в значительной степени, чтобы момент, когда что-то просто останавливается или не попадает в релиз и т. д. Замедление часто необходимо, потому что, если вы предлагаете критическое изменение, необходимы доказательства, чтобы иметь возможность оценить влияние и оправдать такое изменение. Сегодня трудно собрать эти доказательства. Я говорю это просто потому, что предпочитаю доработать функции сейчас, чем спорить о важных изменениях в любой день.

Я никогда не использую ? в именах переменных, и я тоже. Я ожидаю, что некоторые люди это сделают, потому что он может очень хорошо читать в сценарии, а создание ненужных барьеров для входа в PowerShell 7 просто замедляет внедрение. особенно когда многие люди, работающие с PowerShell, не являются разработчиками, которые более привыкли работать через критические изменения.

Во всяком случае, я не намерен замедлять этот процесс - скорее, наоборот. Но я поделился своими мыслями и опытом, поэтому я не буду комментировать дальше, должны ли мы настаивать на радикальных изменениях здесь.

Рассмотрим этот надуманный пример:

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

Такое поведение _ уже_ нарушит предлагаемые изменения. Я бы предпочел последовательный, чистый разрыв, чем сбивающий с толку разрыв, который требует пояснения на полстраницы, чтобы перечислить все возможные исключения, а также когда и где ? внезапно недействителен и где он все еще есть.

@KirkMunro, если PowerShell 7 или более поздней

Работая в нескольких странах из списка Fortune 50, где количество сотрудников исчислялось сотнями тысяч, даже уйти от того, что было по умолчанию в ОС, было проблемой (например, перейти на v5.x). Я еще не видел, чтобы какое-либо место применяло Core ; они предпочли бы просто перейти на Python для обеспечения кросс-совместимости. Включение дополнительных функций Windows также было довольно редкой задачей.

Я думаю, что компании работают с тем, что у них есть, и с базой знаний своих сотрудников, ища новые технологии или языковые версии для решения своих проблем. Некоторым было бы вполне комфортно остаться на v2 навсегда и никогда не касаться командлетов Win10 / Server16, которые значительно облегчают жизнь.

Я хочу сказать, что эти функции не находятся в вакууме. Если вы сделаете язык более эргономичным, люди, заинтересованные в этом инструменте, будут лучше его применять, чтобы быстрее решать возникающие у них проблемы. (См .: C # и рост популярности благодаря большему / большему количеству языковых функций)

Что касается переменных, оканчивающихся на ? - это может быть существенное критическое изменение из-за автоматической переменной $? .

@lzybkr Я подозреваю, что лучший вариант решения этой проблемы - это особый случай, подобный тому, что уже существует для $^ и $$ .

@lzybkr @ TheIncorrigible1 Насколько я помню, _все_ эти переменные явно имеют специальный регистр в токенизаторе. $^ _already_ не является допустимым именем переменной. У токенизатора есть особые случаи для всех из них, прежде чем он начнет искать стандартные имена переменных.

Единственное решение здесь - использовать ¿ :

$ глупо? ¿= 1

Я не знаю, Стив, я твердо нахожусь в толпе interrobang по этому поводу.

$silly?‽=1

@lzybkr - $? $$ и $^ обрабатываются особым образом.

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

Подводя итог, у нас есть эти четыре варианта

  • Большое критическое изменение - не допускать ? в именах переменных.
  • Предпочитайте ?. в качестве оператора. Это означает, что имена переменных, заканчивающиеся на ? должны использовать синтаксис ${variablename} . Все еще серьезное изменение.
  • Предпочитаю старое поведение. Это означает, что для использования ?. и ?[] ${variablename}?.property . Никаких критических изменений, но делает использование новых операторов неудобным.
  • Не вводите новые операторы.

Лично я не предпочитаю первую и последнюю.

Это серьезное изменение версии. Я думаю, что это не лишено смысла здесь менять.

Я думаю, что важно отметить, что основная версия увеличивается, чтобы сигнализировать о готовности заменить Windows PowerShell, то есть указывает на совместимость, а не на поломку. Из оригинального объявления :

Обратите внимание, что основная версия не означает, что мы будем вносить существенные критические изменения.

Варианты 1 и 2 не совпадают? Или переменным по-прежнему будет разрешено использовать ? в случае, если за ними не следует объединяющий нуль или тернарный оператор?

Если это так, я думаю, что у нас могут возникнуть большие проблемы с обработкой логики токенизации / синтаксического анализа без большого количества возвратов. Это может привести к снижению производительности, если переменные оканчиваются на ? .

Учитывая то, что я вижу, вариант 2 кажется общим предпочтением, я не совсем уверен, что понимаю нежелание вносить здесь критическое изменение. Это в любом случае будет активно препятствовать использованию ? в именах переменных, просто вводя сценарии, в которых они не могут использоваться, без включения имени переменной.

Я думаю, что это довольно незначительное изменение, поскольку идут критические изменения, и нарушение согласованности того, что можно и что нельзя использовать в имени переменной, - вероятно, худший вариант, на мой взгляд.

У этих вещей должны быть четкие правила, применимые практически ко всем ситуациям. В настоящее время это так. Мы предлагаем замутить здесь воду и сделать поведение _less_ понятным. Я не вижу ничего хорошего из этого, кроме, возможно, того, что имена переменных, содержащие ? становятся менее используемыми просто потому, что их труднее использовать в некоторых сценариях, что (фактически) возвращает нас к варианту 1 по умолчанию почти ... так что я не вижу особых причин не брать перерыв сейчас и просто избегать двусмысленного поведения.

@ vexx32 Между 1 и 2 есть небольшая разница.

Для # 1 мы запрещаем использовать ? в именах переменных все вместе. Это означает, что $x? = 1 , $x?? = 1 $x?x?x = 1 не будут анализировать.

Для # 2 $x? = 1 все еще действует, но $x?.name эквивалентно ${x}?.name . Это только разбивает имена переменных с ? в конце, которые обращаются к членам. Итак, $x? = 1 , $x?? = 1 $x?x?x = 1 прежнему будут действительными.

Да, я был бы немного обеспокоен токенизацией накладных расходов. Возможно, стоит реализовать обе возможности и провести несколько тестов на скрипте, который достаточно часто использует похожие имена переменных.

Я определенно предпочитаю вариант 1 ... одноразовое критическое изменение, по крайней мере для меня, намного предпочтительнее, чем иметь дело с несоответствиями в том, как это может быть проанализировано в будущем.

Если это так, я думаю, что у нас могут возникнуть большие проблемы с обработкой логики токенизации / синтаксического анализа без большого количества возвратов. Если переменные оканчиваются на?, Это может привести к снижению производительности.

Я разделяю это беспокойство по поводу такой возможности. Использование ? в качестве иногда разделителя токенов для меня кажется неровной линией на языке.

Если это так, я думаю, что у нас могут возникнуть большие проблемы с обработкой логики токенизации / синтаксического анализа без большого количества возвратов. Если переменные оканчиваются на?, Это может привести к снижению производительности.

Это зависит от того, как вы это реализуете. Если вы используете опережающий подход, а не метод токенизации с последующим резервным копированием, все будет в порядке. Вы можете заранее посмотреть, какие символы будут следующими, когда вы встретите ? в имени переменной, и принять решение о том, как вы хотите «обернуть» токен переменной в зависимости от того, что будет дальше. Это не такая уж большая проблема и не требует отката или приводит к заметному снижению производительности.

@ PowerShell / комитет по PowerShell рассмотрел это сегодня, у нас есть пара мыслей:

  • Независимо от того, что мы делаем, мы собираемся провести некоторый анализ нашего корпуса скриптов, чтобы увидеть, как часто люди используют ? в именах переменных.
  • У некоторых из нас есть гипотеза (которую другие хотели бы подтвердить) о том, что пользователи, которые используют ? в своих именах переменных, могут быть менее продвинутыми пользователями (поскольку мы согласны в этой комнате, мы не будем использовать это, потому что потенциальных проблем, которые могут возникнуть). С другой стороны, любой, кто использует описанные здесь функции, сможет понять немного более сложный синтаксис (например, ${foo}?.bar ). Поэтому мы предпочитаем вариант 3, потому что он позволяет избежать критических изменений для менее опытных пользователей. (Но опять же, мы проверим его по первому пункту.)
  • @ daxian-dbw поднял хороший вопрос об усложнении поиска всех ссылок на переменные, когда сценаристы смешивают использование $foo и ${foo} . Однако мы согласились с тем, что это можно исправить в инструментах (например, в расширении VS Code PowerShell), и такие пользователи, как @JamesWTruher, которые используют такие редакторы, как Vim, могут легко сопоставить оба с их синтаксисом поиска.

труднее найти все ссылки на переменные, когда сценаристы смешивают использование $ foo и $ {foo}

Это зависит от того, распознает ли AST имя переменной в зависимости от того, видел ли он фигурные скобки. Я подозреваю, что у любого инструмента, использующего PowerShell AST, здесь не будет проблем с фигурными скобками.

Но для регулярного выражения это определенно означает, что вам нужно быть более внимательными: varname -> \{?varname\}?

@rjmholt я сделал анализ здесь . Краткая разбивка: из почти 400 000 скриптов с 22 000 000+ именами переменных (не уникальных) было только ~ 70 уникальных переменных, оканчивающихся на ? .

Спасибо, @mburszley - для меня это делает его Bucket 3: маловероятное изменение {...} очень прискорбно, параллельно с неудачной потребностью в $(...) около exit / return / throw операторы в контексте && и || .

Чтобы позаимствовать рассуждение из этого вопроса:

Если мы принудительно используем {...} вокруг имен переменных, чтобы вы могли использовать ?. :

  • Новые пользователи не будут ожидать потребности в {...} и не обязательно будут знать, что _it_ это то, что требуется, когда следующее не работает (возможно, _undetected_, если не действует Set-StrictMode -Version 2 или выше): $o = [pscustomobject] @{ one = 1 }; $o?.one

  • Даже если пользователи _do_ узнают о необходимости {...} :

    • Иногда они забывают использовать его из-за противоречащей интуиции необходимости.
    • Когда они вспомнят, это, казалось бы, искусственное требование будет постоянным источником разочарования, тем более что {...} сложно набрать.

Эта проблема отмечена как исправленная, и в ней не было никаких действий в течение 1 дня . Он был закрыт на уборку.

@rjmholt , цитирую вас с https://github.com/PowerShell/PowerShell/issues/10967#issuecomment -561843650:

не нарушать способ анализа существующего действительного синтаксиса было правильным путем. Опять же, изменение - это не просто случай, когда мы принимаем решение поддерживать небольшое количество диких программ - мы внесли множество критических изменений в тех случаях, когда мы думали, что плюсы перевешивают минусы (не то чтобы я лично согласен со всеми из них, или что те оправдывают или не оправдывают других). Проблема в том, что изменение некоторых аспектов токенизатора или парсера означает, что две версии PowerShell больше не будут генерировать один и тот же AST для некоторых сценариев, поэтому две оболочки PowerShell будут «видеть» один и тот же сценарий по-разному. Это означает, что мы даже не можем прочитать синтаксис таким же образом, поэтому нет правила PSScriptAnalyzer, которое вы могли бы написать, чтобы выявить возможные проблемы вокруг него; PSScriptAnalyzer будет видеть различный синтаксис от одной версии PowerShell к другой.

В отличие от C #, PowerShell не может предварительно скомпилировать другой синтаксис в совместимый формат для последующего выполнения, что означает, что изменение синтаксиса привязано к среде выполнения. Как только PowerShell делает синтаксический перерыв, мы сокращаем количество сценариев, которые могут работать с разными версиями, то есть пользователи вынуждены писать два сценария, что является серьезной проблемой для оболочки и языка сценариев. PowerShell должен быть достаточно динамичным, чтобы преодолеть все различия с помощью логики внутри одного скрипта, но синтаксис - это единственная статическая вещь, которая не подлежит обсуждению. И внесение изменений в синтаксис там, где допустимы и до, и после, особенно пагубно, поскольку нет простого способа его обнаружить, для него нет предупреждений, и даже после его выполнения в обеих средах пользователи могут не знать, что произошло другое поведение.

В целом, я могу понять, что такие изменения могут быть очень проблематичными и должны производиться только в том случае, если плюсы перевешивают минусы, важным фактором которых является то, насколько существующий код ломается.

уменьшаем количество скриптов, которые могут работать с разными версиями
это означает, что пользователи вынуждены писать два сценария

Здесь мы говорим о _ новой_ синтаксической функции ( ?. ), поэтому по определению сценарии, которые ее используют, _cannot_ (значимо) работают в более старых версиях - если вы специально не добавляете условные обозначения, которые предоставляют пути кода, совместимые с устаревшей версией, но это вряд ли того стоит - тогда вы просто будете придерживаться устаревших функций.

Да, интерпретация $var?.foo в старых скриптах, которые использовали $var? в качестве имени переменной, не работает, но:

  • ? нельзя использовать как часть идентификатора _ без включения его в {...} _.

  • Поскольку возможность сделать это является неожиданным и, вероятно, даже _ неизвестным_ многим, такие имена переменных чрезвычайно редки в дикой природе, судя по личному опыту, но

    • Даже Ruby разрешает только ?! ) в _end_ идентификаторов, и только идентификаторы _method_, и я подозреваю, что большинство пользователей Ruby знают, что им не следует _не_ предполагать, что другие языки поддерживают тоже самое.

Итак, прагматично говоря:

  • Подавляющее большинство существующего кода не будет затронуто - токен, такой как $var?.foo , просто не встретится.

  • Если вы напишете $var?.foo с новой семантикой, тогда да, запуск этого в более старых версиях может привести к другому поведению (а не к нарушению очевидным образом), в зависимости от того, какой строгий режим действует - но _вы всегда должны в любом случае обеспечить минимальную версию, необходимую для запуска вашего кода по назначению_ ( #requires -Version , ключи манифеста модуля).

В целом, для меня это явный случай изменения корзины 3: технически критичного изменения, которое ломает очень мало существующего кода, предлагая при этом реальные преимущества (или, наоборот, избегая постоянных головных болей из-за неожиданного поведения).

@ mklement0 мы продолжаем экспериментальный доступ с нулевым условием для PS7.0. Возможно, вы сможете открыть новый выпуск, чтобы продолжить обсуждение 7.1?

Звучит хорошо, @ SteveL-MSFT - см. # 11379.

Я призываю всех здесь снова проявить поддержку (или, задыхаясь, не поддерживать).

Была ли эта страница полезной?
0 / 5 - 0 рейтинги