Объединение нулей и доступ с нулевым условием (поглощение нулей) были бы удобными дополнениями к языку.
_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
- см. Таблицу ниже .
@ 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:
$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]
- нет.
$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
.
Я думаю, что это изменение, вероятно, наступило давно.
Разве тернарный оператор не имел той же проблемы, когда решение заключалось в том, чтобы требовать пробелы вокруг оператора или фигурные скобки вокруг имени переменной, чтобы он правильно работал с переменными, заканчивающимися на ?
?
Я ожидал, что с введением этих операторов 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 - $?
$$
и $^
обрабатываются особым образом.
Подводя итог, у нас есть эти четыре варианта
?
в именах переменных.?.
в качестве оператора. Это означает, что имена переменных, заканчивающиеся на ?
должны использовать синтаксис ${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, потому что он позволяет избежать критических изменений для менее опытных пользователей. (Но опять же, мы проверим его по первому пункту.)$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?
в качестве имени переменной, не работает, но:
?
нельзя использовать как часть идентификатора _ без включения его в {...}
_.
Поскольку возможность сделать это является неожиданным и, вероятно, даже _ неизвестным_ многим, такие имена переменных чрезвычайно редки в дикой природе, судя по личному опыту, но
?
(и !
) в _end_ идентификаторов, и только идентификаторы _method_, и я подозреваю, что большинство пользователей Ruby знают, что им не следует _не_ предполагать, что другие языки поддерживают тоже самое.Итак, прагматично говоря:
Подавляющее большинство существующего кода не будет затронуто - токен, такой как $var?.foo
, просто не встретится.
Если вы напишете $var?.foo
с новой семантикой, тогда да, запуск этого в более старых версиях может привести к другому поведению (а не к нарушению очевидным образом), в зависимости от того, какой строгий режим действует - но _вы всегда должны в любом случае обеспечить минимальную версию, необходимую для запуска вашего кода по назначению_ ( #requires -Version
, ключи манифеста модуля).
В целом, для меня это явный случай изменения корзины 3: технически критичного изменения, которое ломает очень мало существующего кода, предлагая при этом реальные преимущества (или, наоборот, избегая постоянных головных болей из-за неожиданного поведения).
@ mklement0 мы продолжаем экспериментальный доступ с нулевым условием для PS7.0. Возможно, вы сможете открыть новый выпуск, чтобы продолжить обсуждение 7.1?
Звучит хорошо, @ SteveL-MSFT - см. # 11379.
Я призываю всех здесь снова проявить поддержку (или, задыхаясь, не поддерживать).
Самый полезный комментарий
@rjmholt я сделал анализ здесь . Краткая разбивка: из почти 400 000 скриптов с 22 000 000+ именами переменных (не уникальных) было только ~ 70 уникальных переменных, оканчивающихся на
?
.