Powershell: Saran: terapkan penggabungan-nol, akses bersyarat nol (perendaman nol), penetapan bersyarat null

Dibuat pada 2 Mar 2017  ·  71Komentar  ·  Sumber: PowerShell/PowerShell

Null-coalescing dan null-conditonal access (null-soaking) akan menjadi tambahan yang berguna untuk bahasa ini.

_Update_: @BrucePay juga menyarankan null-conditional _assignment_ , dengan ?= - lihat komentar di bawah .

Misalnya, alih-alih menulis:

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

seseorang mungkin bisa menulis:

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

Re akses bersyarat null: Dengan Set-StrictMode OFF (default), Anda dapat menggunakan $varThatMayBeNull.Name - tidak perlu sintaks khusus; Namun, jika Set-StrictMode -Version 2 atau lebih tinggi berlaku, $varThatMayBeNull.Name akan _break_ dan di situlah operator bersyarat null ( ?. ) membantu, untuk memberi sinyal maksud eksplisit untuk mengabaikan $null secara ringkas.


Pertanyaan terbuka :

$varThatMayBeNull?[42] menangani kasus di mana variabelnya adalah $null , tetapi jika tidak, elemen array dengan indeks yang ditentukan _ harus ada_.

Oleh karena itu, akan sangat membantu untuk membuat _indexing_ null-conditional - sesuatu yang _not_ dukung oleh C #, secara kebetulan (Anda harus menggunakan .ElementAtOrDefault() ).

Dua pilihan dasar tersebut adalah:

  • Munculkan sintaks tambahan yang secara eksplisit menandakan maksud untuk mengabaikan _index_ yang tidak ada:

    • Pertanyaannya adalah sintaks apa yang harus dipilih untuk ini, mengingat bahwa ?[...] dan [...]? bukan merupakan opsi karena ambiguitas.
    • Mungkin [...?] , tapi itu kelihatannya aneh.
  • Andalkan perilaku yang ada sehubungan dengan mengakses indeks yang tidak ada, seperti yang disiratkan oleh pengaturan Set-StrictMode - lihat tabel di bawah .


Terkait: mengimplementasikan kondisional terner

Issue-Enhancement Resolution-Fixed WG-Language

Komentar yang paling membantu

@rjmholt Saya melakukan analisis di sini . Rincian cepat: Dari hampir 400.000 skrip dengan 22.000.000+ nama variabel (tidak unik), hanya ada ~ 70 variabel unik yang diakhiri dengan ? .

Semua 71 komentar

@ mklement0 Tampaknya contoh kedua bekerja dengan desain tanpa "?".
Mungkin berubah menjadi name() ?

@iSazonov : Poin yang bagus, tetapi hanya berfungsi tanpa ? kecuali Set-StrictMode -Version 2 atau lebih tinggi _not_ berlaku - Saya telah memperbarui posting awal untuk memperjelasnya.

Saya pikir gula sintaksis adalah sesuatu yang dapat digunakan oleh PowerShell yang disukai oleh bahasa lain. +1 di proposal.

Pertimbangkan contoh berikut dari bahasa lain:

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

bahkan

a = b if b else c

lebih baik dari

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

dan sering kali Anda perlu menjelaskan dengan verbose tambahan

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

Membuat orang merasa kotor dan malu.

Menemukan diri saya melakukan ini hari ini sebagai pekerjaan sekitar.

`` PowerShell
$ word = ($ null, "two", "three"). Di mana ({$ _ -ne $ null}, "First")
`` ''

Saya menggunakan pola yang serupa:

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

@kfsone Ada kesalahan kecil dalam contoh Anda $a=(if ($b -ne $null) { $b } else { $c }) . Seharusnya $a=$(if ($b -ne $null) { $b } else { $c }) namun satu-satunya versi PowerShell yang membutuhkan $( ) adalah versi 1. Dari v2, Anda dapat melakukan:

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

@bgshacklett Bukankah maksud Anda $word=($null,'two')[$null -ne 'three'] ?

Agak disayangkan ini telah berubah dari 6,1 menjadi 6,2 menjadi "Masa Depan".

@ TheIncorrigible1 Tidak, jika Anda menyalin dan menempelkan apa yang saya tambahkan di atas, Anda akan melihat bahwa nilai $word disetel ke "dua". Ada lebih banyak detail dalam jawaban Stack Overflow ini di mana saya pertama kali melihat polanya:
https://stackoverflow.com/a/17647824/180813

Sementara perlesque hack-arounds menarik bagi 20 tahun yang lalu saya yang menulis shebang yang mendaftarkan dan / atau mempertanyakan catatan pengguna atau organisasi RIPE-DB, apa yang saya harapkan dari PowerShell adalah sesuatu yang mendorong kolega saya untuk menggunakan bahasa tersebut. daripada menanamkan rasa takut di dalamnya.

Tes lakmus saya adalah ini: Apakah saya ingin membaca ini melalui tablet saya pada jam 3 pagi Tahun Baru sambil menutup telepon dengan CEO di telepon sambil menangis kepada saya berapa juta dolar yang kami hilangkan sedetik.

(Selain itu: ini hanya membesar-besarkan pengalaman sebenarnya sampai saya bekerja di Facebook dan kembali dari kebocoran cepat yang mendesak untuk diberi tahu bahwa, dalam 2 menit saya pergi, lebih banyak orang daripada penduduk Belanda yang telah kosong news feed. Itu bukan kode saya dan kesalahannya adalah perubahan menit dalam semantik return x vs return (x) dalam standar c ++ untuk kasus template yang sangat spesifik, dan "apakah Anda ingin membaca kode ini dengan waktu 2 menit tenggat waktu, kandung kemih penuh dan nasib setiap bakiak yang memakai gambar kucing orang Belanda di bahu Anda ??? "kedengarannya tidak sekeren itu)

Ya. Ada beberapa trik rapi yang mungkin dilakukan di PS yang bagus dalam keadaan darurat atau jika Anda membutuhkan steno satu kali.

Untuk kode yang dapat dipelihara, idealnya kita harus memiliki operator penggabungan-nol yang eksplisit seperti C #. Masalah utama bagi saya adalah - apa yang kita gunakan untuk itu? ? sudah alias Where-Object (saya sangat ingin itu dihapus, ini sangat umum digunakan). Pikiran Anda, % adalah alias ForEach-Object tetapi itu tidak menghalangi operasi modulus, jadi dalam teori setidaknya memiliki ? menjadi operator penggabungan nol juga berpotensi baik; itu hanya akan ditafsirkan seperti itu dalam ekspresi, di mana Where-Object sebenarnya tidak valid.

@ vexx32 :

Setidaknya _syntactically_ ?? seharusnya baik-baik saja, karena kita berbicara tentang mode _expression_, sedangkan ? , sebagai perintah [alias], hanya dikenali dalam mode _argument_.
Tidak yakin apakah penggunaan kembali simbol menyebabkan kebingungan, tetapi ini bukan pertama kalinya sebuah simbol berfungsi ganda dalam konteks yang berbeda.

Anehnya, menggunakan ?. dan ?[] untuk perendaman null secara teknis akan menjadi perubahan besar, karena PowerShell saat ini mengizinkan ? sebagai karakter non-inisial dalam nama variabel.

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

Namun, saya harap ini akan dianggap sebagai Bucket 3: Perubahan

Saya tidak bisa mengatakan saya pernah melihat orang menggunakan? dalam nama variabel ... Saya juga tidak, karena kemungkinan besar akan salah dibaca. Tapi ya, semoga itu bisa digunakan dengan sempurna.

Saya menduga agak terlambat untuk mengemukakan hal ini, tetapi Bash telah menangani ini (dan beberapa kasus lain) dengan fitur Substitusi Parameternya: https://www.tldp.org/LDP/abs/html/parameter-substitution.html.

Meskipun bisa menjadi beruang untuk dipelajari karena banyaknya hal yang dapat dilakukan dengannya, itu sangat kuat. Saya memahami bahwa tidak mungkin menggunakan notasi yang tepat ini karena cara PowerShell menggunakan tanda kurung kurawal dengan variabel, juga tidak akan sesuai dengan nuansa umum bahasa tersebut, tetapi tampaknya seperti titik data yang berguna.

@bg_jakarta :

Ya, substitusi parameter sangat berguna, tetapi, sayangnya, ini tidak hanya berpengaruh pada _learn_, tetapi juga _remember_.

Jadi, meskipun _features_ Bash sering menarik, bentuk _syntactic_ mereka sering kali misterius, sulit diingat, dan tidak cocok untuk PowerShell.

_Brace expansion_ (mis., a{1,2,3} dalam bash berkembang menjadi a1 a2 a3 ) adalah contoh fitur menarik yang ekspresifnya ingin saya lihat di PowerShell, tetapi dengan PowerShell yang sesuai sintaks - lihat # 4286

Saya sangat setuju. Saya mengemukakannya lebih sebagai contoh bagaimana masalah ini telah diselesaikan di tempat lain daripada solusi yang tepat.

Ada satu operator lain yang mungkin perlu dipertimbangkan:

$x ?= 12

yang akan menyetel $x jika tidak disetel (tidak ada). Ini adalah bagian dari "pola penginisialisasi" yang tidak umum dalam bahasa konvensional tetapi untuk bahasa (dengan cakupan dinamis) seperti shell, make tools, dll. Sangat umum untuk memiliki skrip yang menyetel default jika pengguna belum menentukannya . (Meskipun sebenarnya penginisialisasi parameter cukup luas.)

Memperluas ini ke properti:

$obj.SomeProperty ?= 13

akan menambah dan menginisialisasi properti catatan SomeProperty pada objek jika tidak ada.

Dan - untuk bersenang-senang - satu variasi lagi dalam menginisialisasi variabel menggunakan -or :

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

$x ?= 12 sepertinya ide yang bagus.

Terpikir oleh saya bahwa kita mungkin harus menerapkan semua operator ini tidak hanya jika LHS tidak _exist_, tetapi juga jika _tidak ada tetapi kebetulan berisi_ $null (dengan [System.Management.Automation.Internal.AutomationNull]::Value diperlakukan seperti $null dalam konteks ini).

menambahkan dan menginisialisasi properti catatan SomeProperty

Dalam hal itu, $obj.SomeProperty ?= 13 masuk akal bagi saya _hanya_ jika .SomeProperty ada dan berisi $null , mengingat bahwa Anda tidak dapat secara implisit membuat properti bahkan dengan tugas biasa (sebaliknya, untuk _hasthables_ the pembuatan entri implisit masuk akal).

Semua operator yang dibahas perlu membebaskan LHS dari pemeriksaan keberadaan mode ketat.

Saya bertanya-tanya tentang maksud / alasan di balik mengapa strictmode menghentikan Anda mengakses properti yang tidak ada. Apakah maksud untuk menangkap kesalahan ketik seperti $x.pretnd ? Apakah maksud untuk memeriksa asumsi seperti assert(x != null) ? Apakah maksud untuk memblokir secara tidak sengaja menyebarkan $null lebih lanjut dalam kode Anda?

the null-soaking (?.) berguna, untuk menandakan maksud eksplisit untuk mengabaikan $ null secara ringkas.

Bukankah itu yang sinyal . dalam mode nonstrict? Jika Anda ingin bersikap ketat, Anda dapat memeriksa .Name ada terlebih dahulu, dengan tidak memeriksa terlebih dahulu, Anda telah memberi isyarat maksud eksplisit bahwa pemeriksaan tidak penting bagi Anda.

Jika StrictMode memiliki tujuan di mana mengakses properti yang tidak ada dan mengembalikan $null dilarang, maka alasan yang sama tidak akan berlaku untuk ?. , dan itu akan memunculkan pengecualian yang sama untuk alasan yang sama . Jika tidak, mengapa tidak?

Dengan penggabungan nol, Anda dapat menulis:

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

Apakah akan cepat menjadi direkomendasikan atau idiomatis untuk selalu menggunakan ?. untuk setiap referensi properti, karena "berperilaku seperti . , dan tidak akan memberikan pengecualian untuk orang yang menggunakan strictmode"?

Apakah keinginan sebenarnya untuk memiliki strikmode yang dapat dikonfigurasi dengan pengaturan variabel, sehingga misalnya Anda dapat memiliki deklarasi di bagian atas skrip # StrictMode SkipMemberExistenceCheck , atau atribut escape hatch untuk menunjukkan blok unstrict code umumnya? [Saya menduga keinginannya adalah sintaks gaya C # yang singkat, tetapi Anda tahu apa yang saya maksud]

Terima kasih atas pemikirannya, @HumanEquivalentUnit.

Apakah maksud untuk menangkap kesalahan ketik seperti $x.pretnd ?

Saya tidak dapat berbicara tentang maksud desain, tetapi itulah yang masuk akal bagi saya - analog dengan apa yang dilakukan Set-StrictMode -Version 1 untuk _variables_ (hanya).

Dengan variabel, ini tentang _existence_ mereka, bukan apakah nilainya kebetulan $null , dan memeriksa keberadaan properti mengikuti pola yang sama.

Saya menganggapnya sebagai yang paling dekat dengan bahasa scripting dinamis untuk menemukan kesalahan yang akan dilaporkan oleh bahasa terkompilasi yang diketik secara statis pada _compile time_.


Bukankah itu yang terjadi. sinyal sudah dalam mode nonstrict? Jika Anda ingin bersikap ketat, Anda dapat memeriksa .Name sudah ada terlebih dahulu

Ya, tetapi dalam mode non-ketat Anda melupakan pemeriksaan keberadaan yang disebutkan di atas, dan pengujian secara manual jelas cukup rumit - dan selalu lebih lambat daripada fitur bawaan.

dengan tidak memeriksa terlebih dahulu, Anda sudah memberi isyarat maksud eksplisit bahwa pemeriksaan itu tidak penting bagi Anda.

Intinya adalah, dengan Set-StrictMode -Version 2 atau lebih tinggi, Anda mendapatkan:

  • manfaat dari keberadaan anggota memeriksa _ secara default_
  • opsi untuk menyisih, _ sesuai permintaan, secara ringkas_ dengan .?

Anda dapat memiliki deklarasi di bagian atas skrip # StrictMode SkipMemberExistenceCheck , atau atribut escape hatch untuk menunjukkan blok unstrict code secara umum

Terkait: Cakupan dinamis saat ini dari Set-StrictMode bermasalah; lihat draf RFC @lzybkr untuk mengimplementasikan mode ketat _lexical_: https://github.com/PowerShell/PowerShell-RFC/blob/master/1-Draft/RFC0003-Lexical-Strict-Mode.md

manfaat dari pemeriksaan keberadaan anggota secara default

PS berisi kode yang memeriksa anggota, dan mengembalikan $ null ketika mereka tidak ada. Itu adalah keuntungan secara default, yang juga dapat Anda hindari dengan menulis tes keberadaan anggota Anda sendiri dengan $x.psobject.properties... jika Anda mau. StrictMode menghilangkan manfaat itu dan meninggalkan hambatan karena harus menulis tes keberadaan. Kemudian alih-alih memberikan cara yang bagus untuk menulis dengan tepat tes keberadaan anggota, ?. akan memberi Anda solusi ringkas untuk mendapatkan apa yang selalu dilakukan . . Dan jika penting bahwa anggota tersebut ada, Anda masih harus mengkodekannya secara terpisah.

Tapi ini membuat saya bertanya bagaimana dengan pemanggilan metode:

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

yaitu ?. akan berperilaku sama seperti . untuk pencarian properti di non-strictmode, tetapi akan berperilaku berbeda dengan . untuk pemanggilan metode di non-strictmode, membuatnya bernuansa dan tidak pengganti drop-in. Apakah itu berarti bahwa ketika menggunakan ?. Anda sama sekali tidak tahu apakah sebuah metode dipanggil, atau tidak ada yang terjadi? Properti dapat didukung oleh metode pengambil, tetapi saya pikir itu konvensi di DotNet untuk pengambil tidak mengubah keadaan internal, tetapi normal untuk panggilan metode ke status mutasi. Dengan ?. Anda tidak akan tahu jika Anda mengubah status objek?

Saya ingin tahu apakah Anda bisa mendapatkan manfaat yang diinginkan, dan lebih baik, dengan menghasilkan ?? mampu menangani Pengecualian PropertyNotFoundException dan MethodNotFound langsung dari ekspresi di sebelah kiri (tetapi bukan Pengecualian lain yang dimunculkan di dalam metode), serta menangani $ nulls, dan tidak memiliki ?. sama sekali. misalnya

$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

Dan kemudian, alih-alih ?. memanggil anggota atau mengakses properti, ini bisa menjadi cara ringkas untuk menanyakan apakah ada anggota, mengembalikan [bool].

Dengan penambahan sintaks yang sama dari ?? dan ?. Anda dapat menangani lebih banyak situasi, dengan tumpang tindih yang tidak terlalu membingungkan.

StrictMode menghilangkan manfaat itu dan meninggalkan hambatan karena harus menulis tes keberadaan

Hambatan satu orang adalah keuntungan orang lain:
Itu semua tergantung pada apa yang Anda inginkan terjadi _ secara default_:

  • Jika Anda yakin bahwa tidak ada _typos_ dalam kode Anda - dengan segala cara, manfaatkan perilaku _default_ (mode ketat OFF) - dan Anda tidak memerlukan .? (untuk akses _property_ - lihat komentar berikutnya kembali _method calls_ dan _indexing_).

    • Pada catatan _personal_: Saya cenderung menggunakan Set-StrictMode -Version 1 untuk menghindari kesalahan ketik pada nama _variable_, tetapi saya menemukan -Version 2 atau lebih tinggi terlalu mengganggu, terutama karena # 2798 (yang merupakan bug yang tidak tergantung pada proposal ini).
  • Jika Anda ingin memastikan bahwa Anda (a) Anda tidak salah mengeja nama properti dan / atau (b) kode Anda tidak beroperasi secara tidak sengaja pada tipe data selain yang Anda maksudkan, setel mode ketat ke versi 2 atau lebih tinggi .

    • Memang, bahwa _currently_ membuatnya sulit untuk _menyisih_ dari pemeriksaan ini _ sesuai permintaan_,
    • itulah mengapa memperkenalkan akses bersyarat nol diusulkan di sini: untuk membuatnya _mudah_ untuk menyisih sesuai permintaan.

Menguji keberadaan anggota secara eksplisit sebenarnya merupakan kasus penggunaan terpisah yang dapat menjadi kebutuhan terlepas dari mode ketat yang berlaku.

Adapun _panggilan metode_, yang tidak dicakup oleh OP:

_Panggilan metode_ (mis., $varThatMayBeNull.Method() ) dan _indexing_ (mis., $varThatMayBeNull[$index] ) adalah dua kasus di mana bahkan mode ketat dimatikan atau pada versi 1 dapat menguntungkan, mengingat bahwa kedua kasus saat ini _invariably_ menyebabkan kesalahan jika nilai yang diakses adalah $null .

Sintaksnya akan sama dengan properti untuk metode - $varThatMayBeNull?.Method() - dan analog untuk pengindeksan - $varThatMayBeNull?[$index] - seperti di C #.

_Update_: Ada aspek kedua untuk pengindeksan, yaitu jika variabelnya bukan nol, tetapi elemen pada indeks yang diberikan tidak ada (mis., $arr = 0,1; $arr[2] ). Dengan mode ketat versi 2 atau di bawahnya, ini bernilai $null , tetapi di versi 3 atau lebih tinggi hal itu menyebabkan kesalahan, dan alangkah baiknya juga dapat menyisih dari kesalahan ini. Namun, sintaks untuk kasus ini menghadirkan tantangan - lihat OP yang diperbarui, yang saat ini mengusulkan [...?] mungkin aneh.

Dan, ya, saya akan menjadikan akses seperti itu sebagai default ke $null juga, bahkan untuk metode - sekali lagi, Anda _explicitly_ menandakan bahwa tidak apa-apa jika objek yang diakses adalah $null atau jika tidak ada elemen array seperti itu.

Perhatikan bahwa C # tidak memiliki pengindeksan bersyarat nol dalam arti kedua.

Ini memiliki pengindeksan bersyarat nol, hanya tidak seperti yang Anda usulkan. C # memungkinkan (saya cukup yakin, setidaknya ...) array?[0] yang melewati masalah biasa "indeks ke dalam array / koleksi null" dan hanya mengembalikan null.

Tapi ya, saya setuju bahwa ini adalah ide yang bagus. Ini menyelamatkan kita melalui penanganan pengecualian, dan membuat kode cukup jelas dan ringkas.

@ vexx32 , itu adalah _one_ aspek dari pengindeksan bersyarat nol: jika array di array?[0] adalah null , operasi pengindeksan diabaikan - C # juga memilikinya, seperti yang Anda nyatakan.

Saya (update: _also_) berbicara tentang aspek _other_ dari pengindeksan bersyarat null: kasus di mana array dalam array?[0] adalah _not_ null tetapi itu adalah _ elemen pada indeks 0 _ itu tidak ada.

Ini adalah yang terakhir yang tidak bisa diabaikan di C #, sepengetahuan saya, namun saya pikir itu akan berguna juga.

Dapatkah Anda memikirkan terminologi yang memberi dua aspek ini nama yang berbeda?

Kode dari masalah JavaScript lainnya akan berubah dari $_.Description[0].Text menjadi $_?.Description[0?]?.Text yang menurut saya tidak bagus; dan saran saya yang lain tentang bagaimana ?? dapat berperilaku akan membawanya ke $_.Description[0].Text ?? yang secara subyektif lebih baik, dan akan - jika memungkinkan untuk diterapkan - menangani kegagalan di titik pencarian mana pun dalam rantai sekaligus , dan tetap membiarkan Anda memilih apa yang Anda inginkan terjadi secara default, dan memiliki fallback yang berbeda sesuka hati alih-alih dibatasi hanya $null .

Sebagai tambahan, apakah sintaks ?. ini memiliki analog untuk properti dan metode statis, yaitu $t = [int]; $t::MaxValu; $t::Pars("1") , apakah itu akan menjadi ?: atau ?:: ?

Apa perilaku yang diinginkan untuk pengindeksan array dengan lebih dari satu indeks yang ditentukan? $array[0,4?,1,2] mana masing-masing dapat diizinkan untuk gagal, atau $array[0,4,1,2?] dengan hanya keseluruhan lot yang diizinkan untuk berhasil atau gagal?

Pertama-tama saya harus mengambil langkah mundur, karena saya menyadari bahwa saya telah menggabungkan aspek-aspek yang layak dipisahkan, setidaknya secara konseptual:

  • _Null-value_-conditional member atau index access, seperti di C #:

    • Jika nilai yang sedang diakses adalah $null , abaikan upaya untuk mengakses anggotanya atau indeks ke dalamnya dan evaluasi ke $null .
  • _Member-keberadaan_-anggota bersyarat atau akses indeks, khusus untuk PowerShell:

    • Jika nilai yang sedang diakses adalah _non- $null _, abaikan upaya untuk mengakses _members_ yang tidak ada (properti, panggilan metode, pengindeksan) yang tidak ada.

Catatan: Untuk singkatnya saya menggunakan _member_ agak longgar di sini untuk juga mencakup _elements_ objek yang kebetulan merupakan koleksi, yang diakses dengan _indexing_ daripada notasi titik.

Jika Anda yakin tidak ada kesalahan ketik dalam kode Anda - dengan segala cara, manfaatkan perilaku default (mode ketat NONAKTIF) - dan Anda tidak memerlukannya.? (untuk akses properti

@ mklement0 Saya rasa Anda sedang mendiskusikan dari tampilan " satu orang menggunakan mode ketat untuk meningkatkan kode mereka sendiri " dan saya dari tampilan " orang lain dapat menjalankan kode saya dalam mode ketat, perubahan apa yang akan membuat kode saya berfungsi untuk mereka juga? "dan itu membawa saya ke alasan yang berbeda. Dengan ?. akan sangat mudah untuk menggunakannya daripada . dan membuat kode juga berfungsi dalam mode tightmode sehingga saya dapat menggunakannya di mana saja secara biasa; Saya tidak kehilangan apa pun dan mendapatkan kompatibilitas. Saya khawatir semua kode PowerShell akan jelek dengan cara itu karena "berfungsi" dalam lebih banyak kasus.

Tapi ini bukan pengganti drop-in, karena ini membungkam pencarian panggilan metode yang gagal di non-strictmode, dan membungkam pencarian properti yang gagal di mode strictmode - ini menambahkan nuansa fiddly ke pencarian anggota, operasi yang sangat umum. Itu tidak membantu siapa pun yang ingin mendapatkan keuntungan dari pemeriksaan mode ketat dengan membuat plat cetak itu lebih mudah. Itu tidak membantu cukup banyak orang dalam situasi yang cukup, karena kompleksitas yang ditambahkannya. Dan terlalu nyaman untuk membuat kode lebih kompatibel, saya tidak berpikir "abaikan jika Anda tidak menginginkannya" cukup kuat untuk menahannya.

PowerShell dapat melakukan hal-hal yang tidak dilakukan C #, seperti mengatur variabel otomatis, atau memiliki preseden untuk pengecualian yang dilemparkan dan dibungkam di belakang layar. Pasti ada pendekatan yang

@HumanEquivalentUnit Bagaimana cara membungkam hal-hal ini? Anda harus menulis beban penanganan pengecualian dan pemeriksaan nol sebelumnya, sebagai gantinya:

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

v.

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

Dan kasus ini tidak jarang terjadi. Atau Anda hanya membuang $ErrorActionPreference = 'Stop' dan membungkus semuanya dalam try/catch untuk menyederhanakan pemeriksaan null yang merupakan pola yang buruk (logika yang digerakkan oleh pengecualian).

Juga, ini adalah masa depan bahasa, tidak seperti kita kembali ke 5.1 dan mengubah banyak hal. Jika Anda ingin lebih banyak pengadopsi, Anda harus membuatnya lebih mudah untuk membaca kode, yang menurut saya saran ini bisa.

@ mklement0 Saya rasa Anda berdiskusi dari tampilan "_satu orang menggunakan mode ketat untuk meningkatkan kode mereka sendiri_" dan saya dari tampilan "_someone else dapat menjalankan kode saya di strictmode, perubahan apa yang akan membuat kode saya berfungsi untuk mereka juga? _ "

Apakah kita berbicara tentang "set -euo pipefail" (bash tight mode) yang setara?

a- Batasi pencarian variabel (meskipun saya tidak mengerti mengapa menurut Anda pemeriksaan nol sederhana pada pencarian anggota akan menjadi hal yang buruk, pencarian anggota sebenarnya jauh lebih mahal daripada if (result is null) )
b- Gunakan [Strict] pada cakupan / blok kode untuk memberi tahu parser agar memperlakukannya seperti itu,
c- Keketatan didasarkan pada cakupan: kode yang tidak ditandai ketat tidak ketat.

Jika saya menulis kode ketat yang gagal saat Anda menggunakannya, maka salah satu dari kami melakukan kesalahan. Entah saya mereferensikan variabel yang hilang dalam kode yang tidak pernah saya uji atau Anda salah paham terhadap API saya yang dirancang dengan buruk yang bergantung pada keberadaan variabel yang tidak diteruskan ke fungsi saya dan Anda gagal mengisi variabel yang saya harap akan diisi .. .

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

Fungsi "Log" tidak ditandai ketat sehingga tidak mengeluh tentang kesalahan ketik

🤔 Sekarang setelah Anda menyebutkannya, atribut [Strict()] akan menjadi cara _awesome_ untuk mengimplementasikan mode ketat dengan cara yang dibatasi ruang lingkup. Itu perlu disebutkan di utas masalah lain tentang masalah mode ketat, saya akan menggali itu dan menautkan kembali ke sini ...

@ TheIncorrigible1 " Bagaimana cara membungkam hal-hal ini? " Dalam mode non-ketat $null.x diam, $null.x() adalah pengecualian. Dengan ?. seperti yang didiskusikan, $null?.x diam, $null?.x() diam.

Jadi Anda akan memiliki . yang berfungsi seperti C # ?. , kecuali dalam mode ketat di mana ia melempar pengecualian. Maka Anda akan memiliki ?. yang bekerja dalam mode ketat seperti C # ?. dan seperti PowerShell . bekerja dalam mode non-ketat, tetapi yang bekerja berbeda dengan PowerShell . dalam mode non-ketat untuk panggilan metode. Sungguh kombinasi yang mengerikan, (dan kombinasi di mana ?. jelas lebih baik dan lebih berguna di lebih banyak skenario tersebut).

Anda harus menulis beban penanganan eksepsi dan pemeriksaan null sebelumnya, sebagai gantinya: $prop = $item?.Method().PropIwant ?? 'PropActionFailed'

Panggilan metode Anda mungkin melempar, atau mengembalikan $ null dan PropIWant mungkin hilang, Anda masih harus menulis:

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

vs dengan usulan saya ?? (jika memungkinkan untuk dibangun), dan tidak perlu ?. , dan ini mencakup kemungkinan kasus pengecualian Metode jika yang Anda pedulikan hanyalah "berhasil atau tidak" dan tidak ada penanganan kesalahan rinci.

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

Jika Anda ingin lebih banyak pengadopsi, Anda harus membuatnya lebih mudah untuk membaca kode, yang menurut saya saran ini bisa.

Seberapa sering Anda mengetik . di PowerShell? Seberapa sering Anda ingin menjelaskan kepada pengguna baru apa perbedaan antara . dan ?. dan memberi tahu mereka bahwa mereka harus mempertimbangkan perbedaannya setiap kali mereka mengetik . selamanya ?

"Oh, bagaimana itu bisa terjadi?" "Nah di C # . memberikan pengecualian untuk anggota yang hilang, jadi mereka menemukan ?. yang tidak. Itu bagus, jadi mereka melakukannya di PowerShell secara default, . tidak melempar. Kemudian mereka menemukan mode-ketat yang membuat . berperilaku seperti C # dan melempar tetapi hanya dalam konteks itu, Tetapi cara untuk memeriksa anggota secara manual benar-benar bertele-tele dan mengganggu dan tidak ada yang mau mengetiknya; Alih-alih menangani masalah itu secara langsung dan membuatnya lebih nyaman untuk mendapatkan keuntungan dari mode ketat, mereka mengelak dan menggunakan C # ?. sebagai gantinya untuk mendapatkan jalan licik keluar dari ketatnya yang Anda minta, yang agak nyaman untuk Anda, tapi menyebalkan untuk orang lain. Dan Anda masih belum memiliki tes keberadaan anggota, dan manfaat dari strictmode masih bertele-tele dan menyusahkan, tetapi setidaknya Anda tidak perlu menderita karena 'strictmode' memiliki pintu keluar 'mode normal' sekarang". Ih.

Jika saya menulis kode ketat yang gagal saat Anda menggunakannya, maka salah satu dari kami melakukan kesalahan.

meskipun saya tidak mengerti mengapa menurut Anda pemeriksaan nol sederhana pada pencarian anggota akan menjadi hal yang buruk, pencarian anggota yang sebenarnya jauh lebih mahal daripada jika (hasilnya null)

Saya tidak berpikir itu akan buruk, PS non-strictmode sudah melakukan itu, dan saya pikir itu akan menjadi alternatif yang diinginkan untuk ?. diusulkan - sangat berbeda, berguna dalam lebih banyak situasi.

Tetapi perhatikan bahwa di PS Anda dapat melakukan sesuatu yang tidak dapat dilakukan C #:

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

dan tidak ada pengecualian dalam non-strictmode. Ubah angkanya dan lihat berapa lama waktu yang dibutuhkan; dilihat dari kinerjanya dan bagaimana menurut saya itu harus bekerja di belakang layar untuk mengindeks menjadi objek sewenang-wenang, tampaknya sebenarnya ada ~ 100.000 pengecualian yang dimunculkan dan dibungkam, untuk kenyamanan kita. PS tidak selalu membuat pilihan "harus secepat mungkin, mendorong ketidaknyamanan pada pengguna", dan saya suka itu.

@HumanEquivalentUnit Ada banyak fitur dalam setiap bahasa yang mungkin tidak pernah Anda gunakan dalam karier Anda dan jika Anda tidak menyukai gayanya, tidak masalah, Anda tidak perlu menggunakan fitur tersebut. Saya tidak mengerti mengapa Anda menghapus mode ketat; ini adalah praktik yang baik dalam skrip sehingga Anda secara sadar menangani masalah daripada membiarkan bahasa menelannya (dan pada dasarnya, memiliki blok tangkap kosong implisit di mana-mana). Sekali lagi, Anda tetap diperbolehkan untuk tidak menggunakan fitur-fiturnya (mis. Saya tidak pernah menggunakan Out-Default ).

Juga, operatornya adalah ? , bukan ?. ; itu akan bekerja dengan akses indeks juga.

Untuk terus meletakkan dasar untuk diskusi lebih lanjut, izinkan saya merangkum bagaimana mode ketat yang ada memengaruhi akses bersyarat nilai-nol dan keberadaan-keberadaan-bersyarat (istilah yang diperkenalkan di atas ):

Kolom di bawah ini mewakili pengaturan Set-StrictMode , dan nilai kolom menunjukkan:

  • 👍 ... diizinkan
  • 🚫 ... dilarang (menyebabkan kesalahan penghentian pernyataan)

Selain itu: fakta kesalahan hanya _statement-_, bukan _script_-terminating, berkaitan dengan diskusi yang lebih besar seputar penanganan kesalahan PowerShell - lihat https://github.com/PowerShell/PowerShell-Docs/issues/1583.

  • _Akses bersyarat nilai-nol - $obj _dirinya_ adalah $null :

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

Sangat mengherankan bahwa dengan -Off dan -Version 1 , $obj.Prop diperbolehkan, sedangkan $obj[42] tidak diperbolehkan.

  • _Akses bersyarat-keberadaan-anggota - $obj bukan- $null , tetapi anggota / elemen yang sedang diakses tidak ada:

Membangun | -Off | -Versi 1 | -Versi 2 | -Versi 3+
---------- | ---- | ---------- | ---------- | ------------
$ obj.Prop | 👍 | 👍 | 🚫 | 🚫
$ obj [42] (dapat diindeks) | 👍 | 👍 | 👍 | 🚫
$ obj [42] (tidak dapat diindeks) | 👍 | 👍 | 🚫 | 🚫
$ obj.Method () | 🚫 | 🚫 | 🚫 | 🚫

Sangat mengherankan bahwa objek yang secara inheren dapat diindeks (misalnya, array) memungkinkan akses ke elemen yang tidak ada bahkan dengan -Version 2 , sedangkan skalar - di mana PowerShell menyediakan kemampuan pengindeksan demi penanganan terpadu dengan koleksi - tidak.

Operator null-soaking ( null-conditional atau Elvis di C # ) hampir wajib saat menjalankan StrictMode Latest dan mencoba mengakses properti yang mungkin ada atau tidak. Saat ini Anda harus menggunakan trik bodoh seperti ini:

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

ketika Anda _really_ seharusnya sudah bisa menulis:

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

Tolong teman-teman, jika Anda hanya bisa mendapatkan persyaratan nol dari penerapan proposal ini dan hanya untuk properti, itu akan menyelamatkan begitu banyak orang dari rasa sakit.

Saya mulai melihat ini dan menemukan beberapa masalah.

Mari pertimbangkan ?? dan ?=

$x ?= 1 dan $x ?? 1 sepertinya mudah. Tetapi, karena mereka adalah operator, kami perlu mendukung $x?=1 dan $x??1 .

Masalahnya adalah $x? dan $x?? keduanya memvalidasi nama variabel di PowerShell. Satu-satunya cara untuk menghilangkan keraguan adalah ${x}?=1 dan ${x}??1 .

Dan terlebih lagi untuk akses anggota bersyarat ?. dan ?[] , kita harus memiliki ${x}?.name dan ${x}?[0] .
Untuk ini, $x ?.name dan $x ?[0] tidak akan didukung.

Opsi lainnya adalah memperkenalkan perubahan yang melanggar dan tidak mengizinkan ? dalam nama variabel sama sekali.

Bagaimana menurut anda? @bayu_joo

/ cc @rjmholt @ daxian-dbw @JamesWTruher

Saya tidak pernah terlalu _liked_ atau mengerti mengapa ? adalah nama variabel yang valid. Ini membuka pintu untuk nama-nama seperti $Safe? yang umumnya lebih jelas dan tidak terlalu aneh jika ditulis sebagai $IsSafe .

Saya pikir perubahan itu mungkin sudah lama terjadi.

Ini membuka pintu untuk nama-nama seperti $ Safe? yang umumnya lebih jelas dan tidak terlalu canggung jika ditulis sebagai $ IsSafe

Menariknya, saya mengungkapkan sentimen yang berlawanan. Ini adalah tradisi Skema / Ruby klasik.

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

Bukankah operator terner memiliki masalah yang sama, di mana resolusinya memerlukan spasi di sekitar operator atau tanda kurung kurawal di sekitar nama variabel agar dapat berfungsi dengan baik dengan variabel yang diakhiri dengan ? ?

Saya berharap bahwa dengan operator ini diperkenalkan, PowerShell akan memprioritaskan mengenali ? sebagai bagian dari operator dalam sintaks seperti $x?[0] , sehingga pengguna yang menggunakan nama variabel diakhiri dengan ? untuk menyimpan koleksi harus menggunakan sintaks ini sebagai gantinya (karena spasi tidak valid dalam kasus ini): ${x?}?[0] . Ditto untuk $x?.Name dan ${x?}?.Name .

Pilihan lainnya adalah memperkenalkan perubahan yang melanggar dan tidak mengizinkan? dalam nama variabel sama sekali.

👍 Mengingat ini adalah perubahan versi utama (6 menjadi 7), saya pikir ada baiknya melakukan perubahan besar di sini. Saya berharap GitHub memiliki pencarian kode yang lebih baik untuk melihat berapa banyak contoh variabel PS yang diakhiri dengan ? . Saya curiga ini tidak akan terlalu berdampak tetapi alangkah baiknya untuk memverifikasi itu terhadap GitHub. Dalam 14 tahun menggunakan PowerShell, saya tidak pernah menggunakan ? dalam nama variabel tapi mungkin itu hanya saya. :-)

Kapal itu telah berlayar lama sekali, dan saya tidak akan terkejut melihat variabel yang diakhiri dengan ? digunakan dalam skrip hari ini.

Pada titik ini jika kita hanya memprioritaskan parsing ? sebagai bagian dari operator daripada sebagai bagian dari nama variabel ketika berhubungan dengan operator baru ini, orang yang menggunakan nama variabel yang diakhiri dengan ? akan membutuhkan untuk menggunakan {} atau spasi (di mana spasi diperbolehkan) untuk menggunakan variabel tersebut dengan operator ini.

Aneh mendengar ungkapan "kapal itu telah berlayar" dalam konteks ini. Ini adalah perubahan _major version_. Bukan tidak masuk akal untuk ini berubah di sini, saya pikir.

@rkeithhill Saya telah menggunakannya dalam hal-hal pribadi, tetapi berpikir tidak akan jelas untuk pekerjaan kolaboratif karena itu adalah hal yang anti-intuitif bagi pemrogram untuk memiliki simbol sebagai bagian dari nama variabel (mirip dengan menggunakan emoji sebagai variabel)

@KirkMunro memiliki "penguraian yang diprioritaskan" terdengar seperti pintu terbuka untuk bug.

@ vexx32 : Ini tidak masuk akal untuk perubahan yang ? baik selama mereka menggunakan {} lampiran untuk mengidentifikasi nama variabel.

Perhatikan bahwa Anda juga dapat memiliki nama properti yang diakhiri dengan ? . Saat ini jika Anda mencoba melihat properti seperti itu di PowerShell tanpa membungkus nama dalam tanda kutip, Anda akan mendapatkan kesalahan pengurai.

Sebagai contoh:

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

Saya sedikit terkejut karena tidak mengurai hari ini (mengapa tidak mengurai?), Tetapi terlepas dari itu, untuk properti seperti itu Anda perlu menyertakan namanya dalam tanda kutip, dalam hal ini Anda dapat mengikuti kutipan dengan terner, null -coalescing, dll. Operator tanpa spasi dan itu akan bekerja dengan baik. Saya menemukan sintaks ini sangat mirip dengan ${x?}?.name , dan saya setuju dengan pendirian bahwa Anda dapat menggunakan nama variabel / properti jika Anda mau, tetapi nama seperti itu mungkin memerlukan sintaks atau spasi tambahan untuk bekerja dengan ternary atau null - * operator.

@KirkMunro Tidak ada yang bisa menghentikan orang untuk menggunakan variabel-bounds ke depannya jika mereka menginginkan nama variabel esoterik. Saya setuju dengan yang lain karena saya bertanya-tanya apa penggunaan perilaku itu saat ini yang digunakan.

Orang-orang di PowerShell 7 kemungkinan besar sudah menjadi penggemar dan akan sadar akan perubahan yang merusak. Orang yang tidak, masih menggunakan <= v5.1 dan akan terus menggunakannya untuk waktu yang lama; kemungkinan sampai msft menghapusnya dari Windows 10 (tidak pernah).

@KirkMunro Tentu, tetapi menghapusnya dari karakter variabel standar yang diizinkan tidak mencegah pengguna untuk hanya melakukan ${Valid?} sebagai nama variabel. Karena mereka harus melakukannya dengan operator ini, menurut saya akan lebih baik jika konsisten, daripada membuat ? menjadi karakter yang _hanya kadang_ dianggap sebagai bagian dari nama variabel.

Itu sudah _is_ akan menjadi perubahan besar, dan menurut saya yang terbaik adalah setidaknya bersikap konsisten tentang hal itu dan terus melakukannya daripada memperkenalkan tingkat ambiguitas yang lain. 🙂

@adityapatwardhan Saya pikir akan lebih baik jika bahasa menghapus ? sebagai karakter variabel yang valid. Ini akan dengan mudah mengaktifkan operator null-soak / -coalesce dan terner dalam sintaks yang familiar yang menambahkan banyak ergonomi ke proses penulisan skrip.

@KirkMunro memiliki "penguraian yang diprioritaskan" terdengar seperti pintu terbuka untuk bug.

@ TheIncorrigible1 : Kode apa pun dapat membuka pintu bagi bug jika tidak diterapkan dengan benar. Saya hanya berbicara tentang lookahead karakter tunggal sederhana untuk mengidentifikasi apakah PowerShell berjalan ke terner atau operator null- * ketika mem-parsing nama variabel yang tidak tertutup dalam batas variabel dan menemukan karakter ? . Itu tidak rumit, dan tidak membuka pintu untuk lebih banyak bug daripada perubahan kode lainnya.

Orang-orang di PowerShell 7 kemungkinan besar sudah menjadi penggemar dan akan sadar akan perubahan yang merusak. Orang yang tidak, masih menggunakan <= v5.1 dan akan terus menggunakannya untuk waktu yang lama; kemungkinan sampai msft menghapusnya dari Windows 10 (tidak pernah).

@ TheIncorrigible1 : Dasar / bukti apa yang Anda miliki tentang pernyataan itu? PowerShell 7 sedang dalam pratinjau, jadi hari ini hanya digunakan oleh para penggemar. Itu sudah pasti. Namun di luar pratinjau, jika PowerShell 7 atau yang lebih baru menawarkan fitur menarik yang dibutuhkan perusahaan, sambil mendukung fungsionalitas yang mereka butuhkan, mereka akan menggunakan versi tersebut. Itu terutama benar jika PowerShell 7 diinstal dengan OS. Satu-satunya hal yang diminati oleh para penggemar adalah dalam organisasi yang tidak memiliki kebutuhan bisnis untuk apa yang dibawa oleh PowerShell 7.

Itu sudah akan menjadi perubahan yang menghancurkan, dan saya pikir yang terbaik adalah setidaknya konsisten tentang hal itu dan melangkah lebih jauh daripada memperkenalkan tingkat ambiguitas yang lain. 🙂

@ vexx32 Itu meregangkannya. Ini akan menjadi perubahan yang merusak jika Anda memiliki ?? dalam nama variabel, tetapi kemungkinannya jauh lebih jauh daripada memiliki variabel yang namanya diakhiri dengan ? tunggal. Selain itu, bagaimana pengenalan operator null- * sementara masih mendukung ? sebagai skrip pemutusan karakter variabel standar yang diizinkan hari ini?

Dalam pengalaman saya, memecah perubahan untuk yang baik-untuk-dimiliki (yang tampaknya seperti ini) jauh lebih sering ditolak, dan diskusi / argumen di sekitarnya hanya memperlambat proses menyelesaikan sesuatu secara dramatis, untuk titik di mana segala sesuatunya terhenti atau terlewat masuk ke rilis, dll. Perlambatan seringkali diperlukan, karena jika Anda mengusulkan perubahan yang melanggar, bukti diperlukan untuk dapat menilai dampak dan membenarkan perubahan semacam itu. Sulit untuk mengumpulkan bukti itu hari ini. Saya hanya mengatakan ini karena saya akan memilih menyelesaikan fitur sekarang daripada berdebat tentang perubahan yang bagus untuk dimiliki kapan saja.

Saya tidak pernah menggunakan ? dalam nama variabel, saya juga tidak. Saya berharap beberapa orang melakukannya, karena dapat membaca dengan sangat baik dalam skrip, dan memasang penghalang yang tidak perlu untuk masuk untuk PowerShell 7 hanya memperlambat adopsi, terutama ketika banyak orang yang bekerja dengan PowerShell bukanlah pengembang yang lebih terbiasa bekerja melalui perubahan besar.

Bagaimanapun, bukan maksud saya untuk memperlambat proses ini - justru sebaliknya. Tetapi saya telah membagikan pemikiran dan pengalaman saya, jadi saya tidak akan berkomentar lebih lanjut tentang apakah kita harus mendorong perubahan yang menghancurkan di sini atau tidak.

Pertimbangkan contoh yang dibuat-buat ini:

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

Perilaku ini _already_ akan rusak dengan perubahan yang diusulkan. Saya lebih suka jeda yang konsisten dan bersih daripada jeda yang membingungkan yang membutuhkan penjelasan setengah halaman untuk mencantumkan semua kemungkinan pengecualian dan kapan dan di mana ? tiba-tiba tidak valid, dan di mana itu masih.

@KirkMunro jika PowerShell 7 atau lebih baru menawarkan fitur menarik yang dibutuhkan perusahaan, sementara mendukung fungsionalitas yang mereka butuhkan, mereka akan menggunakan versi tersebut. Itu terutama benar jika PowerShell 7 diinstal dengan OS.

Setelah bekerja di beberapa perusahaan Fortune 50 dengan beberapa basis karyawan mencapai ratusan ribu, bahkan menjauh dari apa yang default di OS adalah sebuah tantangan (yaitu, pindah ke v5.x). Saya belum melihat tempat mana pun yang mengadopsi Core ; mereka lebih suka pindah ke Python untuk kompatibilitas silang. Mengaktifkan fitur opsional Windows juga merupakan tugas yang sangat jarang.

Saya pikir perusahaan bekerja dengan apa yang mereka miliki dan basis pengetahuan karyawan mereka daripada mencari teknologi baru atau versi bahasa untuk memecahkan masalah mereka. Beberapa akan sangat puas dengan tetap menggunakan v2 selamanya dan tidak pernah menyentuh cmdlet Win10 / Server16 yang membuat hidup jauh lebih mudah.

Maksud saya dengan semua ini, adalah bahwa fitur-fitur ini tidak berada dalam ruang hampa. Jika Anda membuat suatu bahasa lebih ergonomis, akan terlihat adopsi yang lebih besar oleh orang-orang yang tertarik pada alat untuk menyelesaikan masalah yang mereka hadapi dengan lebih cepat. (Lihat: C # dan pertumbuhan popularitas dengan fitur bahasa yang lebih banyak / lebih baik)

Mengenai variabel yang diakhiri dengan ? - itu bisa menjadi perubahan yang signifikan karena variabel otomatis $? .

@lzybkr Saya menduga kasus terbaik untuk menangani itu adalah kasus khusus seperti yang sudah ada untuk $^ dan $$ .

@ lzybkr @ TheIncorrigible1 Sejauh yang saya ingat, _semua_ variabel tersebut secara eksplisit dikurung khusus di tokenizer. $^ _already_ bukan nama variabel yang valid. Tokenizer memiliki kasus khusus untuk semua itu sebelum mulai mencari nama variabel standar.

Satu-satunya solusi di sini adalah menggunakan ¿ :

$ konyol? ¿= 1

Entahlah Steve, saya tegas berada di kerumunan interrobang yang satu ini.

$silly?‽=1

@lzybkr - sepengetahuan saya $? $$ dan $^ diperlakukan dengan cara khusus.

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

Untuk meringkas, kami memiliki empat opsi ini

  • Perubahan besar yang merusak - tidak mengizinkan ? dalam nama variabel.
  • Lebih suka ?. sebagai operator. Ini berarti nama variabel yang diakhiri dengan ? harus menggunakan sintaks ${variablename} . Masih perubahan besar.
  • Lebih suka perilaku lama. Ini berarti untuk menggunakan ?. dan ?[] , ${variablename}?.property harus digunakan. Tidak ada perubahan yang merusak, tetapi membuat penggunaan operator baru menjadi canggung.
  • Jangan menerapkan operator baru.

Saya pribadi, tidak suka yang 1 dan yang terakhir.

Ini adalah perubahan versi utama. Bukan tidak masuk akal untuk ini berubah di sini, saya pikir.

Saya pikir poin penting yang harus dibuat adalah bahwa versi mayor sedang ditingkatkan untuk memberi sinyal kesiapan untuk menggantikan Windows PowerShell, yang berarti itu menunjukkan kompatibilitas, bukan kerusakan. Dari pengumuman asli :

Perhatikan bahwa versi mayor tidak menyiratkan bahwa kami akan membuat perubahan signifikan yang dapat menyebabkan gangguan.

Apakah opsi 1 dan 2 tidak sama? Atau apakah variabel masih diizinkan untuk menggunakan ? jika tidak ada penggabungan-nol atau operator terner mengikuti mereka?

Jika demikian, saya pikir kita mungkin mengalami banyak masalah dalam menangani logika tokenizing / parsing tanpa banyak pengulangan. Hal ini dapat menyebabkan penurunan kinerja saat variabel diakhiri dengan ? .

Mengingat dari apa yang saya lihat, opsi 2 tampaknya menjadi preferensi umum, saya tidak begitu yakin saya memahami keengganan untuk membuat perubahan yang menghancurkan di sini. Melakukannya dengan cara seperti itu akan secara aktif mencegah penggunaan ? dalam nama variabel, cukup dengan memperkenalkan skenario yang tidak dapat digunakan tanpa menyertakan nama variabel.

Saya pikir ini adalah perubahan yang cukup kecil seiring dengan perubahan yang terjadi, dan jeda dalam konsistensi dari apa yang dapat dan tidak dapat digunakan dalam nama variabel mungkin adalah pilihan yang lebih buruk, menurut saya.

Hal-hal ini harus memiliki aturan yang jelas yang berlaku di hampir semua situasi. Saat ini, inilah masalahnya. Kami mengusulkan untuk membuat air berlumpur di sini dan membuat perilaku _less_ jelas. Saya tidak dapat melihat sesuatu yang baik datang darinya, kecuali mungkin nama variabel yang berisi ? menjadi lebih jarang digunakan hanya karena lebih sulit digunakan dalam beberapa skenario - yang (secara efektif) membawa kita kembali ke opsi 1 secara default, hampir ... jadi saya tidak melihat alasan khusus untuk tidak beristirahat sekarang dan hanya menghindari perilaku ambigu.

@ vexx32 Ada sedikit perbedaan antara 1 dan 2.

Untuk # 1 kami melarang ? untuk digunakan dalam nama variabel secara bersamaan. Ini berarti $x? = 1 , $x?? = 1 $x?x?x = 1 tidak akan diurai.

Untuk # 2, $x? = 1 masih berlaku tetapi $x?.name sama dengan ${x}?.name . Ini hanya memecah nama variabel dengan ? di akhir, yang mengakses anggota. Jadi, $x? = 1 , $x?? = 1 $x?x?x = 1 akan tetap valid.

Ya, saya akan sedikit khawatir tentang tokenizing overhead di sana. Mungkin ada gunanya menerapkan kedua kemungkinan dan melakukan beberapa tolok ukur pada skrip yang menggunakan nama variabel yang cukup mirip.

Preferensi saya jelas-jelas adalah opsi 1 ... perubahan besar yang hanya sekali terjadi, bagi saya setidaknya, jauh lebih disukai daripada harus berurusan dengan ketidakkonsistenan dalam cara menguraikannya ke masa depan.

Jika demikian, saya pikir kita mungkin mengalami banyak masalah dalam menangani logika tokenizing / parsing tanpa banyak pengulangan. Hal ini dapat menyebabkan penurunan kinerja jika variabel diakhiri dengan?.

Saya berbagi kekhawatiran tentang kemungkinan itu. Memiliki ? sebagai pemisah token terkadang terasa seperti garis bergerigi dalam bahasa bagi saya.

Jika demikian, saya pikir kita mungkin mengalami banyak masalah dalam menangani logika tokenizing / parsing tanpa banyak pengulangan. Hal ini dapat menyebabkan penurunan kinerja jika variabel diakhiri dengan?.

Itu tergantung pada bagaimana Anda menerapkannya. Selama Anda mengambil pendekatan lookahead daripada tokenize dan kemudian pendekatan back-up, Anda akan baik-baik saja. Anda dapat melihat ke depan karakter apa yang selanjutnya ketika Anda menemukan ? dalam nama variabel, dan membuat keputusan tentang bagaimana Anda ingin "membungkus" token variabel berdasarkan apa yang berikutnya. Itu tidak terlalu merepotkan dan seharusnya tidak memerlukan pelacakan ulang atau mengakibatkan penurunan kinerja yang nyata.

@ PowerShell / powershell-committee mengulas yang ini hari ini, kami memiliki beberapa pemikiran:

  • Apa pun yang kami lakukan, kami akan melakukan beberapa analisis terhadap korpus skrip kami untuk melihat seberapa sering orang menggunakan ? dalam nama variabel
  • Beberapa dari kami memiliki hipotesis (bahwa orang lain ingin memvalidasi) bahwa pengguna yang menggunakan ? dalam nama variabel mereka mungkin adalah pengguna yang kurang mahir (seperti yang kami sepakati di ruangan ini kami akan menjauh darinya karena masalah potensial yang bisa timbul). Di sisi lain, siapa pun yang menggunakan fungsionalitas yang dijelaskan di sini akan dapat memahami sintaks yang sedikit lebih rumit (seperti ${foo}?.bar ). Oleh karena itu, kami lebih memilih opsi 3 karena ini menghindari perubahan yang merusak pada pengguna yang kurang berpengalaman ini. (Tapi sekali lagi, kami akan memvalidasinya per poin pertama.)
  • @ daxian-dbw mengangkat poin bagus tentang mempersulit untuk menemukan semua referensi variabel ketika skrip mencampur penggunaan $foo dan ${foo} . Namun, kami setuju bahwa ini dapat diperbaiki dalam perkakas (seperti ekstensi VS Code PowerShell), dan pengguna seperti @JamesWTruher yang menggunakan editor seperti Vim dapat dengan mudah mencocokkan keduanya dengan sintaks pencarian mereka.

lebih sulit untuk menemukan semua referensi variabel ketika skrip mencampur penggunaan $ foo dan $ {foo}

Itu tergantung pada apakah AST membedakan nama variabel berdasarkan apakah ia melihat tanda kurung. Saya menduga bahwa alat apa pun yang menggunakan PowerShell AST tidak akan mengalami masalah dengan kawat gigi di sini.

Tetapi untuk regex, itu berarti Anda harus lebih waspada: varname -> \{?varname\}?

@rjmholt Saya melakukan analisis di sini . Rincian cepat: Dari hampir 400.000 skrip dengan 22.000.000+ nama variabel (tidak unik), hanya ada ~ 70 variabel unik yang diakhiri dengan ? .

Terima kasih, @mburszley - bagi saya yang menjadikannya Bucket 3: Perubahan {...} sangat disayangkan, sejajar dengan kebutuhan yang tidak menguntungkan untuk $(...) sekitar exit / return / throw pernyataan dalam konteks && dan || .

Meminjam alasan dari masalah itu:

Jika kami memaksa penggunaan {...} sekitar nama variabel hanya agar Anda dapat menggunakan ?. :

  • Pengguna baru tidak akan mengharapkan kebutuhan {...} dan belum tentu tahu bahwa _it_ adalah yang diperlukan jika hal berikut gagal (mungkin _undetected_, kecuali Set-StrictMode -Version 2 atau lebih tinggi berlaku): $o = [pscustomobject] @{ one = 1 }; $o?.one

  • Bahkan setelah pengguna _do_ mengetahui tentang perlunya {...} :

    • Mereka kadang-kadang akan lupa menggunakannya, karena kebutuhannya yang berlawanan dengan intuisi.
    • Jika mereka ingat, persyaratan yang tampaknya artifisial ini akan terus menjadi sumber frustrasi, terutama karena {...} sulit untuk diketik.

Masalah ini telah ditandai sebagai diperbaiki dan tidak ada aktivitas selama 1 hari . Itu telah ditutup untuk keperluan rumah tangga.

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

tidak melanggar cara kami mengurai sintaks valid yang ada adalah cara yang tepat untuk melakukannya. Sekali lagi, perubahan di sana bukan hanya kasus kami membuat keputusan untuk mendukung sejumlah kecil program liar di luar sana - kami telah membuat banyak perubahan besar dalam kasus di mana kami pikir pro lebih besar daripada kontra (bukan berarti saya pribadi setuju dengan semuanya, atau bahwa mereka melakukan atau tidak membenarkan orang lain). Masalahnya adalah bahwa mengubah beberapa aspek tokenizer atau parser berarti bahwa dua versi PowerShell tidak akan lagi menghasilkan AST yang sama untuk beberapa skrip, jadi dua PowerShell akan "melihat" skrip yang sama secara berbeda. Itu berarti kami bahkan tidak dapat membaca sintaks dengan cara yang sama, jadi tidak ada aturan PSScriptAnalyzer yang dapat Anda tulis untuk mengambil kemungkinan masalah di sekitarnya; PSScriptAnalyzer akan melihat sintaks yang berbeda dari satu versi PowerShell ke versi berikutnya.

Tidak seperti C #, PowerShell tidak dapat melakukan pra-kompilasi sintaks yang berbeda ke format yang kompatibel untuk eksekusi nanti, yang berarti bahwa perubahan sintaksis ditambatkan ke runtime. Setelah PowerShell membuat jeda sintaksis, kami mengurangi jumlah skrip yang dapat bekerja pada versi yang berbeda, yang berarti pengguna dipaksa untuk menulis dua skrip, yang merupakan masalah serius untuk shell dan bahasa skrip. PowerShell seharusnya cukup dinamis untuk melewati semua perbedaan dengan logika di dalam satu skrip, tetapi sintaksnya adalah satu-satunya hal statis yang tidak dapat dinegosiasikan yang kita miliki. Dan membuat perubahan sintaks di mana sebelum dan sesudah valid sangat berbahaya, karena tidak ada cara sederhana untuk mendeteksinya, tidak ada peringatan untuk itu dan bahkan setelah mengeksekusinya di kedua lingkungan, pengguna mungkin tidak tahu bahwa terjadi perilaku yang berbeda.

Secara umum, saya dapat menghargai bahwa perubahan seperti itu bisa sangat bermasalah dan hanya boleh dilakukan jika kelebihannya lebih besar daripada kekurangannya, salah satu faktor pentingnya adalah seberapa banyak kode yang ada rusak.

kami mengurangi jumlah skrip yang dapat bekerja pada versi yang berbeda
artinya pengguna dipaksa untuk menulis dua skrip

Kita berbicara tentang fitur sintaksis _new_ di sini ( ?. ), jadi menurut definisi skrip yang menggunakannya _cannot_ (artinya) berjalan pada versi yang lebih lama - kecuali Anda secara khusus menambahkan kondisional yang menyediakan jalur kode yang kompatibel dengan versi lama, tetapi itu tampaknya tidak sepadan - Anda hanya akan tetap menggunakan fitur lama.

Ya, interpretasi $var?.foo dalam skrip lama yang menggunakan $var? sebagai nama variabel akan rusak, tetapi:

  • ? seharusnya tidak pernah diizinkan sebagai bagian dari pengenal _tanpa melampirkannya dalam {...} _.

  • Karena dapat melakukannya tidak terduga dan mungkin bahkan _unknown_ bagi banyak orang, nama variabel seperti itu sangat jarang di alam liar, berbicara dari pengalaman pribadi, tetapi analisis @mburszley memberikan bukti yang lebih nyata .

    • Bahkan Ruby hanya mengizinkan ? (dan ! ) di _end_ pengenal, dan hanya ada _method_ pengenal, dan saya curiga bahwa sebagian besar pengguna Ruby sadar bahwa mereka harus _not_ menganggap bahwa bahasa lain mendukung hal yang sama.

Jadi, secara pragmatis:

  • Sebagian besar kode yang ada tidak akan terpengaruh - token seperti $var?.foo tidak akan ditemukan.

  • Jika Anda menulis $var?.foo dengan semantik baru, maka ya, menjalankannya pada versi yang lebih lama dapat menghasilkan perilaku yang berbeda (daripada melanggar dengan cara yang jelas), tergantung pada mode ketat apa yang berlaku - tetapi _Anda harus selalu terapkan versi minimum yang diperlukan untuk menjalankan kode Anda sebagaimana dimaksud_ ( #requires -Version , kunci manifes modul).

Secara keseluruhan, bagi saya ini adalah kasus yang jelas dari perubahan ember 3: perubahan teknis yang merusak kode yang ada saat ini sangat sedikit sambil menawarkan manfaat nyata (atau, sebaliknya, menghindari sakit kepala abadi karena perilaku yang tidak terduga).

@ mklement0 kami menyimpan eksperimental akses Bersyarat Null untuk PS7.0. Mungkin Anda dapat membuka terbitan baru untuk melanjutkan diskusi ini untuk 7.1?

Kedengarannya bagus, @ SteveL-MSFT - lihat # 11379.

Saya mendorong semua orang di sini untuk kembali menunjukkan dukungan (atau, terkesiap, non-dukungan) di sana.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat