Rust: Masalah pelacakan untuk RFC 2046, label-break-value

Dibuat pada 27 Feb 2018  ·  135Komentar  ·  Sumber: rust-lang/rust

Ini adalah masalah pelacakan untuk RFC 2046 (rust-lang/rfcs#2046).

Langkah:

Pertanyaan yang belum terselesaikan:

B-RFC-implemented B-unstable C-tracking-issue F-label_break_value T-lang

Komentar yang paling membantu

@tanpa perahu

Saya ingin menghindari penambahan yang lebih luas, pilihan yang sangat fleksibel ke kotak alat aliran kontrol Rust. Saya hanya tertarik untuk menambahkan aliran kontrol yang ditargetkan pada kasus penggunaan tertentu yang penting, dan memiliki dampak ergonomis yang tinggi.

Saya setuju dengan prinsip ini, dan menurut saya fitur ini memenuhi standar tersebut (aliran kontrol yang sudah dikenal yang ditargetkan pada kasus penggunaan yang penting dan spesifik). Ada beberapa kali ketika saya telah meninjau atau menulis kode seperti contoh yang diberikan di atas di mana saya merasa bahwa ini adalah cara paling bersih dan paling mudah dibaca untuk menulis kode ini. Menggunakan kembali konstruksi aliran kontrol yang ada seperti loop dengan break tanpa syarat pada akhirnya menyesatkan pengguna, dan fungsi yang diterapkan segera seringkali tidak mencukupi karena penggunaan ? , await! , atau konstruksi aliran kontrol perantara lainnya.

Menggunakan loop + trailing break membingungkan, dan kita sebaiknya memilih agar pengguna menyatakan niat mereka yang sebenarnya daripada mengharuskan mereka untuk menyalahgunakan alat yang dibuat untuk gaya aliran kontrol yang berbeda. Ini mirip dengan fakta bahwa kita bahkan memiliki konstruksi loop , sementara bahasa lain puas dengan while true { ... } . Melakukan hal ini memungkinkan untuk menulis kode yang mengekspresikan maksud yang lebih jelas dan sebagai hasilnya lebih mudah dibaca.

Selain itu, fitur ini adalah sesuatu yang selalu saya harapkan dimiliki Rust, mengingat bahwa kami telah memberi label-sebagian besar-hal-lain-dan-hal-berlabel-, fakta bahwa Anda tidak dapat memberi label atau memecahkan blok tampaknya membingungkan dan salah padaku.

TL;DR: Saya pikir fitur ini mendukung kasus penggunaan dunia nyata yang hanya dapat ditulis sebaliknya melalui pernyataan bersarang berat- if atau dengan menyalahgunakan konstruksi lain seperti loop-break-value. Ini adalah tambahan kecil untuk sintaks permukaan yang membuat blok berperilaku seperti yang saya harapkan dan memungkinkan saya untuk menulis kode yang saya maksud daripada sesuatu yang jauh lebih hackier.

Semua 135 komentar

Menggunakan "kembali" akan memiliki implikasi yang menarik untuk label ? (coba operator tanda tanya hal).

Gunakan kembali sebagai kata kunci alih-alih istirahat?

@mark-im dan @joshtriplett telah berbicara menentang pengembalian, tetapi saya akan bergabung mengingat bahwa itu tampaknya masih merupakan pertanyaan yang belum terselesaikan.

break (dan lanjutkan) hanya dapat digunakan dengan loop.
Jika Anda dapat memecahkan sesuatu, Anda dapat melanjutkannya. (Saya tidak berpikir ada sintaks yang jelas untuk dipilih untuk melanjutkan di blok.)

Dalam C, C++, Java, C#, JavaScript, dan mungkin lebih banyak bahasa, Anda biasanya break menggunakan pernyataan switch untuk mencegah kesalahan. Karat telah memecahkan ini jauh lebih baik dengan | dalam pola tetapi orang yang berasal dari bahasa tersebut tidak akan benar-benar melihat break sebagai sesuatu yang hanya untuk for loop. Terutama karena Java dan JavaScript mengekspos fitur melalui break juga dan bukan return .

Argumen "aturan untuk diingat" bekerja ke arah lain dengan sangat baik. Dari apa yang saya tahu itu adalah kesamaan dari bahasa yang disebutkan serta Rust yang kembali hanya berlaku untuk fungsi dan tidak ada yang lain. Jadi jika Anda melihat pengembalian, Anda tahu bahwa suatu fungsi sedang ditinggalkan.

Memberi label pada blok tidak menyebabkan kesalahan pada jeda tanpa label yang ada

Pertama, saya pikir ini sangat jarang terjadi karena fitur istirahat berlabel diakui bukan sesuatu yang akan digunakan 10 kali per 1000 baris. Lagi pula, itu hanya akan berlaku untuk jeda tak berlabel yang akan melintasi batas blok, bukan jeda tak berlabel di dalam blok. Kedua, pengguna Rust sudah terbiasa dengan keluhan/pesan error dari compiler, mereka akan dengan senang hati memperbaikinya! Ketiga (ini adalah poin terkuat menurut saya), jika alih-alih memberi label pada blok Anda membungkusnya menjadi satu lingkaran, Anda sudah perlu berhati-hati terhadap jeda yang tidak berlabel dan tidak ada pesan kesalahan yang dengan mudah mencantumkan pernyataan break, Anda punya untuk berburu mereka sendiri :).

Terutama karena Java dan JavaScript mengekspos fitur melalui break juga dan tidak kembali.

Ini bagi saya adalah titik pembunuh. istirahat dari blok adalah hal dalam banyak bahasa. kembali dari blok ... tidak begitu banyak.

Secara pribadi, saya berbagi pandangan @joshtriplett tentang penggunaan break alih-alih return , tetapi bagi saya sepertinya diskusi belum diselesaikan di RFC... Jika Anda percaya pertanyaannya diselesaikan di tim lang, centang kotak dengan catatan =)

Hanya mengatakan bahwa saya sedang mengerjakan ini. Tidak perlu instruksi mentor. Hanya untuk tidak menduplikasi upaya apa pun. Harapkan PR segera.

Saya masih mendukung return daripada break , tetapi saya dapat setuju untuk tidak setuju di sini. Pertanyaan diselesaikan.

Saat ini (dengan rustc 1.28.0-nightly (a1d4a9503 2018-05-20) ) rustc tidak mengizinkan unsafe pada blok berlabel. Apakah ini diharapkan?

@topecongiro Ya, saya yakin ini disengaja bahwa saat ini hanya diperbolehkan di blok biasa. Ini mungkin berubah di masa depan, tetapi mengingat ini adalah fitur tingkat rendah dan tidak biasa, saya cenderung menjadikannya fitur daripada batasan. (Pada ekstrem, saya tentu tidak ingin else 'a: { .)

Pasti setuju. Aliran kontrol yang tidak aman + tidak biasa terdengar seperti sesuatu yang mengecilkan hati.

Namun, dalam keadaan darurat, Anda dapat menggunakan:

'a: {
unsafe {...}
}

Benar?

Sebenarnya, meskipun tidak membuat lingkup leksikal baru, itu bukan blok. Seluruh if-else adalah sebuah blok (agak). Jadi tidak, Anda tidak akan mendapatkan else 'a: { Anda akan mendapatkan 'a: if ... else { .

else berisi blok (ekspresi). tidak ada "lingkup leksikal baru" tanpa blok.
Posisi sintaks permukaan yang lebih buruk dari else adalah 'a: while foo 'b: {...} .
(cukup menarik, continue 'a adalah break 'b , kita mungkin ingin mengandalkan itu setidaknya secara internal)

(cukup menarik, continue 'a adalah break 'b , kita mungkin ingin mengandalkan itu setidaknya secara internal)

Itu pengamatan yang bagus!

Saya pikir label harus menjadi bagian dari ekspresi yang mengandung blok, bukan blok itu sendiri. Kami sudah memiliki preseden untuk ini dengan loop . (Seperti yang terjadi, blok biasa itu sendiri juga merupakan ekspresi yang mengandung blok. Tapi hal-hal seperti if dan loop adalah ekspresi yang mengandung blok, saya kira.)

(Hal-hal seperti while atau for seharusnya tidak mendukung label-break-value, karena mereka dapat atau tidak dapat mengembalikan nilai berdasarkan apakah mereka menyelesaikan secara normal atau dengan break .)

@eddyb

(cukup menarik, lanjutkan 'a is break' b, kita mungkin ingin mengandalkan itu setidaknya secara internal)

Hanya jika break 'b memeriksa ulang kondisi loop...

@mark-im Ini setara dengan 'a: while foo {'b: {...}} , break tidak akan memeriksa kondisi loop, loop itu sendiri akan memeriksanya, karena kondisi loop diperiksa sebelum setiap iterasi dari blok tubuh.

Woah, menurut saya itu _sangat_ tidak intuitif. Saya berharap break 'b pada dasarnya goto 'b , artinya kita tidak pernah keluar dari badan loop dan kondisinya tidak diperiksa lagi...

Oh :man_facepalming: Begitu...

Inilah mengapa saya tidak suka berlabel break/continue :/

Yah, kami secara khusus tidak memiliki kemampuan untuk melabeli blok bagian dalam yang aneh ini, jadi saya tidak melihat masalahnya. break selalu berarti "keluar dari blok ini" dan, mengingat batasan di atas, tidak ada cara untuk itu berarti apa pun selain "masuk ke tempat setelah tanda kurung kurawal yang terkait."

Kebingungan saya tidak khusus untuk blok batin yang aneh, tetapi saya tidak benar-benar ingin membuka kembali diskusi. Itu sudah terjadi dan komunitas memutuskan untuk menambahkannya.

Oke, saya mengerti aksesibilitas adalah masalah besar dengan bahasa pemrograman ... namun, istirahat berlabel sangat berguna jika Anda menulis kode seperti saya.

Jadi, bagaimana kita bisa membuat jeda berlabel lebih mudah diakses?

Jadi, bagaimana kita bisa membuat jeda berlabel lebih mudah diakses?

Itu pertanyaan yang bagus. Beberapa ide yang saya miliki:

  • Kita harus mengumpulkan beberapa contoh bagaimana orang menggunakan ini di alam liar. Kita bisa mencari pola yang tidak diinginkan atau kebiasaan malas.
  • Kita harus memiliki gaya berpendirian ketika dianggap praktik yang buruk untuk menggunakan label break/continue.
  • Kami mungkin dapat menambahkan serat untuk beberapa pola yang dapat diubah menjadi kombinator loop/iterator secara mekanis (walaupun saya tidak dapat memikirkan pola seperti itu dari atas kepala saya).

Sebagai sampel pertama (diakui bias), pertemuan terakhir (dan pertama) saya dengan break berlabel dalam kode nyata tidak luar biasa: https://github.com/rust-lang/rust/pull/48456/files#diff -3ac60df36be32d72842bf5351fc2bb1dL51. Saya dengan hormat menyarankan bahwa jika penulis asli telah melakukan sedikit lebih banyak upaya, mereka dapat menghindari penggunaan label break dalam kasus itu sama sekali... Ini adalah contoh dari jenis praktik yang ingin saya hindari jika memungkinkan.

Itu... tidak berlabel break?

Mengenai bagaimana break dan continue desugar ke dalam ini, yang juga disebutkan dalam diskusi RFC asli oleh penulis RFC; lihat https://github.com/rust-lang/rfcs/pull/2046#issuecomment -312680877

Saya kira nama break kurang optimal, tetapi sudah mapan untuk loop. Pendekatan yang lebih "berprinsip" adalah menggunakan sintaks return 'a value , yang segera melanjutkan eksekusi "setelah" blok 'a , menggunakan nilai value untuk blok itu.

@mark-im "tidak menggunakan fitur karena tidak dapat diakses" bukan "membuat fitur tersebut dapat diakses".

Bagaimana kita bisa men-tweak istirahat berlabel sehingga saya mendapatkan kekuatan ekspresif penuh bahasa sementara pada saat yang sama Anda berhenti mengeluh bahwa otak Anda tidak dapat memproses hal-hal kontrol aliran serta kompiler?

(Juga, kode yang Anda tautkan sepertinya tidak ada hubungannya dengan RFC 2046/label-break-value... apakah Anda mungkin menautkan kode yang salah?)

Itu... tidak berlabel break?

(Juga, kode yang Anda tautkan sepertinya tidak ada hubungannya dengan RFC 2046/label-break-value... apakah Anda mungkin menautkan kode yang salah?)

Itu benar, itu adalah lanjutan berlabel normal sebelum saya mengubahnya, tetapi saya pikir masalah yang sama ada (dan mungkin lebih buruk karena aliran kontrol sisa rutinitas mungkin dipengaruhi oleh nilai yang Anda kembalikan).

@mark-im "tidak menggunakan fitur karena tidak dapat diakses" bukan "membuat fitur tersebut dapat diakses".

Bagaimana kita bisa men-tweak istirahat berlabel sehingga saya mendapatkan kekuatan ekspresif penuh bahasa sementara pada saat yang sama Anda berhenti mengeluh bahwa otak Anda tidak dapat memproses hal-hal kontrol aliran serta kompiler?

Maaf, saya tidak bermaksud mengeluh. Jika saya satu-satunya orang yang merasa seperti ini, saya tidak keberatan minggir.

IMHO, ini adalah masalah mendasar dengan label break/continue: ini _terlalu_ ekspresif, dan satu-satunya cara yang saya tahu untuk menguranginya adalah dengan merekomendasikan penggunaan sebagai "gaya yang baik" (apa pun artinya). Misalnya, "hanya gunakan break berlabel dengan nilai dari awal atau akhir badan loop (bukan di tengah)." Ini berarti bahwa kemungkinan cara untuk keluar dari loop dengan nilai mudah dikenali dan dipikirkan.

Inilah cara saya menghindari goto/labeled break dalam bahasa lain: https://Gist.github.com/SoniEx2/fc5d3614614e4e3fe131/#file -special-lua-L4-L72

Apakah itu lebih mudah dibaca?

Jika demikian, mungkin kita dapat menemukan semacam sistem bersyarat berdasarkan blok berlabel. Mirip dengan ini , mungkin.

Maksud dari break dan continue yang tidak berlabel adalah untuk menyediakan kasus-kasus di mana Anda tidak dapat dengan mudah meletakkan kondisi/nilai di header loop. Beberapa loop jauh lebih mudah, mudah dibaca, cepat, dll. Dengan jeda di tengah.

Titik berlabel break dan continue dalam loop serupa - terkadang satu-satunya alternatif adalah memperkenalkan variabel baru, fungsi baru (dengan demikian menyalahgunakan return ), atau beberapa perubahan lain yang hanya membuat segalanya lebih sulit untuk diikuti, namun sayangnya-berbelit-belit istirahat berlabel mungkin.

Tetapi kedua fitur itu bukan tentang topik ini. Mereka cukup universal, justru karena peningkatan yang mereka tawarkan untuk mengekspresikan aliran kontrol yang kompleks secara inheren. Utas ini bukan tentang keluar dari blok non-loop. Ini tentu saja lebih baru, dan orang mungkin tidak tahu untuk mencari break luar loop, meskipun membutuhkan label berarti sinyal masih ada setelah Anda tahu artinya.

Inilah yang saya maksud tentang contoh Anda, @mark-im- itu adalah penggunaan yang cukup standar dari loop berlabel, daripada blok berlabel.

Pendekatan yang lebih "berprinsip" adalah dengan menggunakan sintaks return 'a value, yang segera melanjutkan eksekusi "setelah" blok 'a, menggunakan nilai nilai untuk blok itu.

Catatan tambahan tentang break vs return : Saya lebih suka break karena ini adalah aliran kontrol statis. return bersifat dinamis, karena ia kembali ke pemanggil, yang mungkin ada di mana saja. Artinya, "Saya telah menyelesaikan tanggung jawab saya, tidak ada tempat lain untuk melihat apa yang saya lakukan." break selalu pergi ke suatu tempat yang secara leksikal dalam lingkup, seperti halnya dengan loop.

Saya pikir return 'label expr membaca dengan sangat baik dari perspektif "lakukan apa yang saya katakan" karena dapat dianggap sebagai "return expr to the location 'label" . Saya tidak berpikir break 'label expr dibaca dengan baik dalam perspektif ini...

Dalam isolasi dari bahasa pemrograman lain, karena itu saya mungkin menganjurkan return 'label expr . Namun, mengingat aliran kontrol dalam bahasa lain, menggunakan kembali return tiba-tiba menjadi pilihan yang jauh lebih tidak layak dan ini membuat saya mendukung break 'label expr .

Saya dengan tegas berpendapat bahwa itu seharusnya break 'label expr dan bukan return 'label expr . Melakukan sebaliknya akan sama sekali tidak konsisten dengan penggunaan break 'label dalam loop.

@SoniEx2 Saya pikir saya lebih suka cuplikan yang Anda posting, terutama karena variabel adalah cara yang baik untuk mendokumentasikan invarian loop. OTOH, Dimungkinkan untuk melakukan hal yang sama dengan nama label (yaitu setiap kali blok berlabel ini dimasukkan, P invarian berlaku). Saya kira ini adalah tempat di mana akan lebih baik untuk memiliki beberapa contoh kode lagi dari alam liar ...

Usulan stabilisasi

Fitur ini diimplementasikan di https://github.com/rust-lang/rust/pull/50045 oleh @est31 dan telah digunakan setiap malam sejak 16-05-2018 (+17 minggu) sehingga cukup matang untuk stabilisasi. Selain itu, tidak ada laporan masalah sejak PR yang menerapkan ini digabung. Semua pertanyaan yang belum terselesaikan juga telah diselesaikan sejak itu, dan ada konsensus kuat bahwa break harus menjadi sintaks permukaan alih-alih return .

Jadi, saya pindah untuk menstabilkan nilai label-break (RFC 2046).

@rfcbot gabung

Laporan

  • Gerbang fitur:

    • https://github.com/rust-lang/rust/blob/master/src/test/ui/feature-gates/feature-gate-label_break_value.rs

    • https://github.com/rust-lang/rust/blob/master/src/test/ui/feature-gates/feature-gate-label_break_value.stderr

  • Diagnostik: https://github.com/rust-lang/rust/blob/master/src/librustc_passes/diagnostics.rs#L285
  • Tes:

    • https://github.com/rust-lang/rust/blob/master/src/test/ui/label/label_break_value_continue.rs

    • https://github.com/rust-lang/rust/blob/master/src/test/ui/label/label_break_value_unlabeled_break.rs

    • https://github.com/rust-lang/rust/blob/master/src/test/ui/label/label_break_value_illegal_uses.rs

    • https://github.com/rust-lang/rust/blob/master/src/test/ui/lint/unused_labels.rs

    • https://github.com/rust-lang/rust/blob/master/src/test/ui/run-pass/for-loop-while/label_break_value.rs

TODO sebelum FCP

@rfcbot mengkhawatirkan FIXME-in-tests

File tes terakhir saat ini memiliki FIXME:

// FIXME: ensure that labeled blocks work if produced by macros and in match arms

Ini harus diselesaikan sebelum menstabilkan.
Saya menulis beberapa tes untuk memeriksa bahwa perilaku yang diharapkan wrt. FIXME sebenarnya diimplementasikan:

// run-pass

#![feature(label_break_value)]

#[test]
fn lbv_match_test() {
    fn test(c: u8, xe: u8, ye: i8) {
        let mut x = 0;
        let y = 'a: {
            match c {
                0 => break 'a 0,
                v if { if v % 2 == 0 { break 'a 1; }; v % 3 == 0 } => { x += 1; },
                v if { 'b: { break 'b v == 5; } } => { x = 41; },
                _ => {
                    'b: {
                        break 'b ();
                    }
                },
            }
            x += 1;
            -1
        };

        assert_eq!(x, xe);
        assert_eq!(y, ye);
    }

    test(0, 0, 0);
    test(1, 1, -1);
    test(2, 0, 1);
    test(3, 2, -1);
    test(5, 42, -1);
    test(7, 1, -1);
}

#[test]
fn lbv_macro_test() {
    macro_rules! mac1 {
        ($target:lifetime, $val:expr) => {
            break $target $val;
        };
    }
    let x: u8 = 'a: {
        'b: {
            mac1!('b, 1);
        };
        0
    };
    assert_eq!(x, 0);
    let x: u8 = 'a: {
        'b: {
            if true {
                mac1!('a, 1);
            }
        };
        0
    };
    assert_eq!(x, 1);
}
// compile-fail

#![feature(label_break_value)]

fn lbv_macro_test_hygiene_respected() {
    macro_rules! mac2 {
        ($val:expr) => {
            break 'a $val;
        };
    }
    let x: u8 = 'a: {
        'b: {
            if true {
                mac2!(2);
            }
        };
        0
    };
    assert_eq!(x, 2);

    macro_rules! mac3 {
        ($val:expr) => {
            'a: {
                $val
            }
        };
    }
    let x: u8 = mac3!('b: {
        if true {
            break 'a 3;
        }
        0
    });
    assert_eq!(x, 3);
    let x: u8 = mac3!(break 'a 4);
    assert_eq!(x, 4);
}

Pengujian serupa harus ditambahkan sebelum kita beralih dari FCP yang diusulkan ke FCP.

Anggota tim @Centril telah mengusulkan untuk menggabungkan ini. Langkah selanjutnya adalah peninjauan oleh sisa tim yang ditandai:

  • [x] @Centril
  • [x] @aturon
  • [x] @cramertj
  • [x] @eddyb
  • [ ] @joshtriplett
  • [x] @nikomatsakis
  • [ ] @nrc
  • [x] @pnkfelix
  • [x] @scottmcm
  • [ ] @tanpa perahu

Kekhawatiran:

  • biaya-manfaat (https://github.com/rust-lang/rust/issues/48594#issuecomment-422235234)
  • FIXME-in-tests (https://github.com/rust-lang/rust/issues/48594#issuecomment-421625182)
  • kasus penggunaan (https://github.com/rust-lang/rust/issues/48594#issuecomment-422281176)

Setelah mayoritas pengulas menyetujui (dan tidak ada yang keberatan), ini akan memasuki periode komentar terakhirnya. Jika Anda menemukan masalah besar yang belum diangkat pada titik mana pun dalam proses ini, silakan angkat bicara!

Lihat dokumen ini untuk info tentang perintah apa yang dapat diberikan oleh anggota tim yang ditandai kepada saya.

@rfcbot memperhatikan biaya-manfaat

Dari proposal RFC FCP :

Kelompok lain merasa bahwa "manfaat biaya" dari fitur ini pada bahasa tersebut tidak cukup berhasil. Dengan kata lain, peningkatan kompleksitas yang akan dibawa oleh fitur -- dengan kata lain, kemungkinan orang akan benar-benar menggunakannya dan Anda harus membaca kode mereka, saya kira, serta ukuran keseluruhan bahasa -- tidak sepadan dengan kegunaannya.

Saya masih tidak berpikir kita harus memiliki fitur ini sama sekali. Sejak diterapkan apakah sudah banyak digunakan? Dalam kasus yang telah digunakan, apakah menggunakan fungsi secara signifikan lebih buruk? Jika ada manfaat di sini, apakah itu lebih besar daripada biaya membuat bahasa lebih besar dan lebih kompleks?

@nrc Saya berbagi perhatian yang sama. Saya mengerti argumen untuk membuatnya tersedia sehingga makro dapat menggunakannya, tetapi pada saat yang sama, saya lebih suka tidak memiliki ini sama sekali.

Saya tidak ingin argumen vulkanisir dari RFC benang asli, tapi saya berpikir bahwa ini adalah titik masuk akal untuk bertanya tentang pengalaman dengan fitur ini. Apa kegunaan yang telah dilihatnya?

parser tulisan tangan, kebanyakan... (Saya suka parser tulisan tangan saya >.<)

akan lebih berguna/lebih mudah digunakan dengan berlabel-propagate ( try_foo() 'bar? ).

@rfcbot menyangkut kasus penggunaan

Meringkas beberapa diskusi tentang Discord: Kami ingin melihat kasus penggunaan konkret untuk ini, dari kode aktual, yang tidak terlihat lebih jelas ketika ditulis ulang untuk tidak menggunakan fitur ini.

~FWIW, implementasi EXPR is PAT bergantung pada break 'label value yang tersedia setidaknya di AST, saya tidak tahu bagaimana desugaring dapat bekerja tanpanya.
Implementasi EXPR? di compiler bergantung pada break 'label value juga.~

~ Ini semacam blok bangunan dasar untuk fitur aliran kontrol yang lebih besar, jadi mungkin tetap perlu diimplementasikan di kompiler.
Jadi "biaya" di sini mungkin hanya membuatnya tersedia dalam sintaksis permukaan.~

EDIT: Saya benar-benar salah mengartikan masalah ini, saya pikir ini tentang loop { ... break 'label value ... } , bukan block { ... break 'label value ... } .
Saya tidak pernah memiliki kesempatan untuk mencoba yang ini karena saya selalu lupa bahwa itu sudah diterapkan.

@petrochenkov Berbicara dengan @joshtriplett di Discord, mereka menunjukkan bahwa mereka khawatir tentang kompleksitas yang dihadapi pengguna, bukan implementasi bahasa.

Saya pikir peningkatan kompleksitasnya minimal: bagi pembaca, harus jelas apa artinya ini karena konsepnya sudah ada dalam loop, dll.
Jika tidak, saya harus menggunakan loop dengan pernyataan break tanpa syarat, yang kurang jelas dan bahkan ada clippy lint (never_loop) tentang ini. Jadi menurut saya ada manfaatnya.

Adapun kasus penggunaan, topik itu sudah muncul di RFC. Saya menunjukkan kasus penggunaan saya di sini . Lihat juga use case yang dicantumkan oleh @scottmcm langsung di bawah ini. Mungkin ada lebih banyak di utas, idk. @joshtriplett apakah itu menyelesaikan pertanyaan kasus penggunaan?

Saya setuju dengan @nrc dan @joshtriplett & saya juga ingin menyampaikan masalah proses di sini: kami untuk sementara menerima RFC ini dengan peringatan eksplisit bahwa stabilisasi diblokir saat meninjau kembali pertanyaan yang diajukan oleh @nrc dan @joshtriplett , tetapi pertanyaan @Centril proposal penggabungan tidak menyebutkan masalah pemblokiran ini sama sekali, dan memperlakukan ini sebagai penggabungan "fitur telah dipanggang" yang sangat standar. Saya tidak menyalahkan @Centril untuk ini, tetapi gangguan proses: jika kita akan menerima fitur sementara dengan pemblokir yang belum terselesaikan pada stabilisasi, kita perlu melacak pemblokir tersebut.

Itu mengkhawatirkan saya dalam hal seluruh proses kami untuk melihat bahwa ini berlangsung 2 setengah hari tanpa masalah pemblokiran yang diangkat, dan dengan sebagian besar anggota tim telah mencentang kotak mereka. Bisa dibayangkan, karena kami tidak lagi membutuhkan konsensus aktif dari semua anggota, bahwa ini bisa masuk ke FCP tanpa pemblokiran bahkan dinaikkan. Ini terasa seperti subversi dari perjanjian sebelumnya yang membuat saya setuju dengan penggabungan RFC, dan saya pikir itu sepenuhnya disebabkan oleh pelacakan informasi yang tidak memadai.

@withoutboats Ya, tepatnya. Ini membuat saya agak kurang cenderung, di masa depan, untuk menerima hal-hal atas dasar "kami akan XYZ selama proses stabilisasi", sampai kami memiliki beberapa proses di tempat yang membuatnya sangat tidak mungkin untuk dilewatkan.

@tanpa perahu

Saya tidak menyalahkan @Centril untuk ini, tetapi gangguan proses: jika kita akan menerima fitur sementara dengan pemblokir yang belum terselesaikan pada stabilisasi, kita perlu melacak pemblokir tersebut.

Permintaan maaf tetap; Saya tidak menyadari peringatan itu, tetapi saya seharusnya memeriksa hal-hal seperti itu ketika saya membuat masalah pelacakan.

Ini terasa seperti subversi dari perjanjian sebelumnya yang membuat saya setuju dengan penggabungan RFC, dan saya pikir itu sepenuhnya disebabkan oleh pelacakan informasi yang tidak memadai.

Saya seharusnya membuat pertanyaan yang belum terselesaikan untuk itu; Saya percaya kesalahan proses terjadi pada saat itu.
Adapun bagaimana meningkatkan proses; Saya pikir penting bahwa pertanyaan yang belum terselesaikan sampai ke _teks_ RFC; menjadi jauh lebih sulit untuk menemukan mereka sebaliknya;)


Adapun proposal fcp-merge; Saya pribadi berpikir itu akan berguna untuk alasan keseragaman dan untuk digunakan oleh makro. Namun, jika Anda yakin terlalu dini untuk mengusulkan stabilisasi; jangan ragu untuk membatalkan proposal :)

@est31

Jika tidak, saya harus menggunakan loop dengan pernyataan break tanpa syarat,

Atau restrukturisasi kode untuk menghindari keduanya.

Saya menunjukkan kasus penggunaan saya di sini .

Mengapa tidak mengganti break 'pseudo_return dengan return Ok(vectors); ?

seperti yang saya sebutkan di sini , ini berguna untuk parser tulisan tangan (bahkan tanpa berlabel-propagate ( try_foo() 'bar? )).

label-break-value memungkinkan imperatifisasi yang mudah dari kode fungsional lainnya. umumnya, kode imperatif cenderung lebih mudah dibaca daripada kode fungsional.

Atau restrukturisasi kode untuk menghindari keduanya.

Tentu saja, Rust sedang turing selesai. Tapi restrukturisasi mungkin agak sulit. Secara keseluruhan, Anda dapat menolak hampir semua fitur gula (dan ini adalah fitur gula) atas dasar "Anda bisa menggunakan cara yang ada".

Mengapa tidak mengganti break 'pseudo_return dengan return Ok(vektor);?

Sebenarnya dalam hal ini Anda benar, seseorang dapat mengganti istirahat dengan pengembalian Ok. Tetapi dalam kasus lain Anda mungkin ingin melakukan pemrosesan setelahnya, dll. Pemeriksa pinjaman bekerja dengan buruk melintasi batas-batas fungsi, Anda tidak dapat memfaktorkan setiap blok tersebut ke dalam suatu fungsi.

Bagaimanapun, saya telah memecah keheningan saya tentang mengomentari fitur bahasa melalui cara resmi, dan saya menyesalinya. Semua poin yang sama, diulang lagi dan lagi. Omong kosong ini membuang-buang waktuku, maaf. Jadi jangan mengharapkan komentar lebih lanjut dari saya.

@est31 Saya sangat menghargai Anda memberikan detail; Terima kasih.

Ada masalah aksesibilitas untuk menguji dan menggunakan hal-hal ini, karena persyaratan Rust malam.

Saya menargetkan stabil. Saya harap ini bisa diselesaikan suatu hari nanti.

Jika kita ingin menggunakan kasus, inilah yang saya tekan beberapa waktu lalu; pada dasarnya penjabaran dari @est31 "lakukan pemrosesan setelahnya": Saya menulis lexer yang menangani awalan literal string C++ (dalam kasus C++ yang sebenarnya, ledakan kombinatorial { L , u8 , u , U , }{ R , }), dan token multi-byte yang dengan "celah" dalam jumlah byte yang digunakan (tidak yakin apakah yang masuk akal tanpa Contoh). Fungsi get_token saat ini terlihat seperti ini:

fn get_token(&mut self) -> Token {
    match decode_byte(self.source) {
        // ...

        // repeat four times with small variations for b'U', b'L', and b'R':
        Some((b'u', rest)) => match decode_byte(rest) {
            Some((b'"', rest)) => self.string_literal(Utf16String, rest),
            Some((b'\'', rest)) => self.char_constant(Utf16Char, rest),
            Some((b'R', rest)) => match decode_byte(rest) {
                Some((b'"', rest)) => self.raw_string_literal(Utf16String, rest),
                _ => self.identifier(rest),
            },
            Some((b'8', rest)) => match decode_byte(rest) {
                Some((b'"', rest)) => self.string_literal(Utf8String, rest),
                Some((b'\'', rest)) => self.char_constant(Utf8Char, rest),
                Some((b'R', rest)) => match decode_byte(rest) {
                    Some((b'"', rest)) => self.raw_string_literal(Utf8String, rest),
                    _ => self.identifier(rest),
                },
                _ => self.identifier(rest),
            },
            _ => self.identifier(rest),
        },

        // ...

        // the "gap" mentioned above is here: single-byte '.' and triple-byte '...' but no double-byte '..':
        Some((b'.', rest)) => match decode_byte(rest) {
            Some((b'0'..=b'9', rest)) => self.number(rest),
            // note the _inner to avoid shadowing the outer `rest` used by the inner `Dot` case:
            Some((b'.', rest_inner)) => match decode_byte(rest_inner) {
                Some((b'.', rest)) => self.make_token(Ellipsis, rest),
                _ => self.make_token(Dot, rest),
            },
            _ => self.make_token(Dot, rest),
        },

        // ...
    }
}

Perhatikan piramida _ => self.identifier(rest) s (diulang empat kali untuk u , U , R , dan L ) dan _ => self.make_token(Dot, rest) s, membentuk semacam gaya penerusan lanjutan di mana identifier , string_literal , dll. semua juga harus memanggil make_token .

Saya ingin mengkonsolidasikan hal-hal kembali ke gaya kurang kelanjutan-y menggunakan break -from-block, dan hampir melakukannya melalui label loop s, tetapi menganggap versi itu terlalu aneh untuk dibaca. Untuk lebih spesifik:

  • Saya akan memindahkan semua panggilan make_token ke satu lokasi setelah match decode_byte(self.source) , dan menggariskannya- kecil dan berisi unsafe dengan invariannya didukung oleh get_token .
  • Saya akan menggunakan break 'label self.string_literal(..) untuk hubungan arus pendek setelah menemukan " atau ' , dan kemudian menggabungkan semua panggilan self.identifier(..) ke akhir lengan pertandingan itu .

    • Saya mungkin juga dapat membuat linearisasi ledakan kombinatorial awalan- periksa u / u8 / U / L , lalu periksa R . Ini menggunakan lebih sedikit break 'label s, tetapi masih sedikit.

  • Saya akan menggunakan break 'label (Ellipsis, rest) sirkuit pendek sekali menemukan ... , dan kemudian digabungkan kedua (Dot, rest) s sampai akhir lengan pertandingan.

Secara keseluruhan, ini pada dasarnya adalah "ratakan aliran kontrol dengan if + pengembalian awal," tanpa persyaratan mengekstraksi sesuatu menjadi fungsi yang terpisah. Itu sangat berharga dalam hal ini karena beberapa alasan:

  • Sebagian besar fungsi ini akan menjadi fungsi kecil sekali pakai tanpa nama bagus, hanya berfungsi untuk membuat hal-hal menjadi lebih tidak mudah dibaca daripada gaya lanjutan-y ini.
  • Beberapa dari fungsi ini akan memerlukan banyak parameter tambahan yang jika tidak hanya akan menjadi penduduk lokal langsung dengan tipe yang disimpulkan.

    • Atau sebagai alternatif, penutupan, yang dalam beberapa kasus ini akan menyebabkan masalah peminjam.

  • Seperti yang saya sebutkan di atas, ada invarian keamanan yang ditegakkan di seluruh fungsi di sini. Semakin banyak garis lurus, kode state-machine di sini, semakin baik, terutama saat orang kembali lagi nanti untuk membuat perubahan kecil untuk jenis token baru.

Saya akan menulis semuanya tetapi saya kira saya tidak pernah melakukan upaya itu (mungkin karena saya mengalami semua masalah yang saya sebutkan di atas) dan saya sudah menghabiskan cukup banyak kata di sini. :)

@SergioBenitez dapatkah Anda menguraikan penggunaan label_break_value http://rocket.rs/ dan pandangan Anda tentang stabilisasi?

@Centril Tentu! Inilah intinya:

fn transform(request: &Request, data: Data) -> Transform<Outcome<_, _>> {
    let outcome = 'o: {
        if !request.content_type().map_or(false, |ct| ct.is_form()) {
            break 'o Forward(data);
        }

        let mut form_string = String::with_capacity(min(4096, LIMIT) as usize);
        if let Err(e) = data.read_to_string(&mut form_string) {
            break 'o Failure(FormDataError::Io(e));
        }

        Success(form_string)
    };

    Transform::Borrowed(outcome)
}

Menggunakan fitur ini, saya menghindari:

  • Memisahkan blok menjadi fungsi yang berbeda untuk "pengembalian" awal.
  • Menambahkan Transform::Borrowed ke setiap nilai "kembali" di blok.
  • Kemungkinan kesalahan jika Transform yang berbeda dikembalikan dalam kasus yang berbeda.

    • Catatan: Ini adalah invarian khusus untuk Rocket dan potongan kode ini.

Saya cukup senang melihat bahwa ini ada. Inilah tepatnya yang ingin saya tulis. Karena itu, saya dapat dengan jelas menulis ini secara berbeda agar tidak bergantung pada fitur ini.

@SergioBenitez Terima kasih! Saya ingin tahu apakah Anda dapat (akhirnya) menulis ulang ini dengan try { .. } ? Seperti:

fn transform(request: &Request, data: Data) -> Transform<Outcome<_, _>> {
    Transform::Borrowed(try {
        if !request.content_type().map_or(false, |ct| ct.is_form()) {
            Forward(data)?;
        }

        let mut form_string = String::with_capacity(min(4096, LIMIT) as usize);
        if let Err(e) = data.read_to_string(&mut form_string) {
            Failure(FormDataError::Io(e))?;
        }

        form_string
    })
}

@Centril Ya, itu akan berhasil selama hanya ada satu jalur sukses, yang terjadi di sini.

Atau restrukturisasi kode untuk menghindari keduanya.

Dengan melakukan ini, Anda berisiko menambahkan cabang tambahan atau panggilan subrutin yang tidak dapat diselesaikan oleh pengoptimal. Bagi saya, transformasi aliran kontrol seperti itu tampaknya menjadi tugas yang cukup rumit.

Dalam kasus yang telah digunakan, apakah menggunakan fungsi secara signifikan lebih buruk? Jika ada manfaat di sini, apakah itu lebih besar daripada biaya membuat bahasa lebih besar dan lebih kompleks?

Sebuah fungsi kecil mungkin digariskan, tetapi bagaimanapun, Anda akan mendapatkan kode yang tidak perlu mengasapi atau mengatakan, duplikasi kode konyol.

Saya lebih suka kode biner yang paling elegan. Anda dapat melakukannya dengan aliran kontrol yang sedikit lebih maju, hampir sama dengan pengembalian awal dari suatu fungsi.

Saya ingin tahu apakah Anda dapat (akhirnya) menulis ulang ini dengan try { .. }? Seperti:
[...]

Itu terlihat sedikit membingungkan, karena cabang diperkenalkan, hanya untuk dioptimalkan. Tetapi dalam beberapa situasi seseorang mungkin membutuhkan keduanya. Dengan demikian, memiliki

'a: {try{...}}

atau

'a: try {...}

akan menyenangkan.

Kami ingin melihat kasus penggunaan konkret untuk ini, dari kode aktual, yang tidak terlihat lebih jelas saat ditulis ulang untuk tidak menggunakan fitur ini.

Silakan mempermalukan saya:

Ini mungkin bukan kode terbaik, tetapi saya ingin semuanya berjalan dengan baik.

Saya ingin secara eksperimental menyatakan kembali loop utama sebagai mesin status dalam hal gaya penerusan lanjutan. Tapi kelanjutan dan panggilan ekor yang dipaksakan adalah topik lain.

Akan sangat menyenangkan melihat fitur ini stabil. Saya memiliki banyak kasus penggunaan di mana sintaks ini menyederhanakan dan memperjelas maksud secara signifikan. Untuk bagian panjang yang melibatkan melakukan operasi yang salah dan membuka bungkus hasilnya, sintaks ini luar biasa.

Saya setuju dengan @zesterer bahwa stabilisasi fitur ini akan bermanfaat bagi ekosistem dan membuat pola tertentu tidak terlalu mengganggu untuk ditulis :+1:

FWIW, saya baru-baru ini menggunakannya di kompiler untuk pertama kalinya.
Polanya sama seperti pada contoh sebelumnya - kami memeriksa beberapa kondisi dan berhenti melakukan apa yang kami lakukan jika salah satunya benar.
https://github.com/rust-lang/rust/blob/21f26849506c141a6760532ca5bdfd8345247fdb/src/librustc_resolve/macros.rs#L955 -L987

@erickt juga menulis beberapa kode yang ingin menggunakan ini untuk alasan yang sama: memeriksa beberapa kondisi, keluar setelah salah satunya menjadi salah. Anda dapat memalsukan ini dengan segera-disebut-penutupan atau let _: Option<()> = try { ... None?; .. }; tetapi keduanya cukup hacky.

@withoutboats @nrc @joshtriplett Apakah Anda memiliki pemikiran tentang kasus penggunaan yang dibawa sejauh ini oleh berbagai orang?

Ping @withoutboats @nrc @joshtriplett :) -- pertemuan terakhir kami membahas kemungkinan bahwa Anda semua mungkin mencoba untuk menulis ulang beberapa contoh yang diberikan di atas dan menunjukkan kepada kami bagaimana Anda akan menyusunnya.

Saya merasa terdorong oleh posting blog greydon untuk menulis komentar di sini tentang mengapa saya tidak ingin menstabilkan fitur ini. Saya merasa agak tidak adil bagi saya untuk menyetujui eksperimen ini; sulit untuk membuktikan yang negatif tetapi saya tidak tahu contoh kode seperti apa yang dapat mengatasi penentangan saya untuk menambahkan bentuk aliran kontrol ini ke bahasa.

Keberatan saya secara keseluruhan adalah bahwa saya hanya berpikir Rust tidak memerlukan konstruksi aliran kontrol percabangan yang lebih terbuka. Kami memiliki kecocokan dan pengulangan, dan kemudian di atas tipe data aljabar, gula sintaksis, abstraksi fungsi, dan makro untuk membuat array besar pola aliran kontrol untuk ditangani oleh pengguna biasa. Ini sudah terasa seperti membelok ke luar biasa, dan saya pribadi harus mengadopsi beberapa aturan untuk mengelola kompleksitas pohon keputusan (misalnya, saya memiliki aturan untuk tidak pernah meraih kombinator sebagai pass pertama: hanya jika sudah jelas setelah sebenarnya akan lebih baik sebagai kombinator).

Saya ingin menghindari penambahan yang lebih luas, pilihan yang sangat fleksibel ke kotak alat aliran kontrol Rust. Saya hanya tertarik untuk menambahkan aliran kontrol yang ditargetkan pada kasus penggunaan tertentu yang penting, dan memiliki dampak ergonomis yang tinggi. Konstruksi ini menurut saya memiliki atribut yang persis terbalik: ini dapat diterapkan secara luas, sangat dapat diterapkan, dan hanya sedikit lebih nyaman daripada alternatifnya.

Selain itu, saya pikir fitur ini memiliki kualitas lain yang sangat negatif: ketidakteraturan karena kompatibilitas ke belakang. Sangat tidak teratur untuk break untuk keluar dari blok hanya jika mereka diberi label, ketika itu keluar dari loop yang tidak berlabel. Ini membuat fitur lebih sulit untuk dipahami daripada jika itu biasa, memperburuk atribut negatif persis di tempat yang menurut saya paling buruk - dapat dipahami.

Saya juga berpikir ada banyak fitur yang jauh lebih penting untuk difokuskan, dan karena kami memiliki perbedaan yang jelas dalam hal ini, saya lebih suka menunda pertimbangan apa pun daripada mencoba melalui proses konsensus yang panjang tentang proposal ini.

Saya pikir hal yang benar untuk dilakukan adalah menemukan setiap peti yang menggunakan fitur ini dan menulis ulang kode agar tidak menggunakan fitur ini.

@withoutboats Terima kasih telah dengan sangat efektif mengartikulasikan banyak keberatan yang sama yang saya pegang juga.

Saya akan maju dan berani di sini:

@rfcbot batal
@rfcbot tunda

@joshtriplett proposal dibatalkan.

Anggota tim @joshtriplett telah mengusulkan untuk menunda ini. Langkah selanjutnya adalah peninjauan oleh sisa tim yang ditandai:

  • [ ] @Centril
  • [ ] @aturon
  • [ ] @cramertj
  • [ ] @eddyb
  • [x] @joshtriplett
  • [ ] @nikomatsakis
  • [ ] @nrc
  • [ ] @pnkfelix
  • [ ] @scottmcm
  • [x] @withoutboats

Tidak ada kekhawatiran saat ini terdaftar.

Setelah mayoritas pengulas menyetujui (dan tidak ada yang keberatan), ini akan memasuki periode komentar terakhirnya. Jika Anda menemukan masalah besar yang belum diangkat pada titik mana pun dalam proses ini, silakan angkat bicara!

Lihat dokumen ini untuk info tentang perintah apa yang dapat diberikan oleh anggota tim yang ditandai kepada saya.

@tanpa perahu

Saya ingin menghindari penambahan yang lebih luas, pilihan yang sangat fleksibel ke kotak alat aliran kontrol Rust. Saya hanya tertarik untuk menambahkan aliran kontrol yang ditargetkan pada kasus penggunaan tertentu yang penting, dan memiliki dampak ergonomis yang tinggi.

Saya setuju dengan prinsip ini, dan menurut saya fitur ini memenuhi standar tersebut (aliran kontrol yang sudah dikenal yang ditargetkan pada kasus penggunaan yang penting dan spesifik). Ada beberapa kali ketika saya telah meninjau atau menulis kode seperti contoh yang diberikan di atas di mana saya merasa bahwa ini adalah cara paling bersih dan paling mudah dibaca untuk menulis kode ini. Menggunakan kembali konstruksi aliran kontrol yang ada seperti loop dengan break tanpa syarat pada akhirnya menyesatkan pengguna, dan fungsi yang diterapkan segera seringkali tidak mencukupi karena penggunaan ? , await! , atau konstruksi aliran kontrol perantara lainnya.

Menggunakan loop + trailing break membingungkan, dan kita sebaiknya memilih agar pengguna menyatakan niat mereka yang sebenarnya daripada mengharuskan mereka untuk menyalahgunakan alat yang dibuat untuk gaya aliran kontrol yang berbeda. Ini mirip dengan fakta bahwa kita bahkan memiliki konstruksi loop , sementara bahasa lain puas dengan while true { ... } . Melakukan hal ini memungkinkan untuk menulis kode yang mengekspresikan maksud yang lebih jelas dan sebagai hasilnya lebih mudah dibaca.

Selain itu, fitur ini adalah sesuatu yang selalu saya harapkan dimiliki Rust, mengingat bahwa kami telah memberi label-sebagian besar-hal-lain-dan-hal-berlabel-, fakta bahwa Anda tidak dapat memberi label atau memecahkan blok tampaknya membingungkan dan salah padaku.

TL;DR: Saya pikir fitur ini mendukung kasus penggunaan dunia nyata yang hanya dapat ditulis sebaliknya melalui pernyataan bersarang berat- if atau dengan menyalahgunakan konstruksi lain seperti loop-break-value. Ini adalah tambahan kecil untuk sintaks permukaan yang membuat blok berperilaku seperti yang saya harapkan dan memungkinkan saya untuk menulis kode yang saya maksud daripada sesuatu yang jauh lebih hackier.

@cramertj Maaf, saya agak bingung. Kedengarannya seperti Anda dan @withoutboats / @joshtriplett mengatakan kebalikan dari satu sama lain?

(fwiw, saya setuju dengan @withoutboats /@joshtriplett)

@mark-im Saya tidak setuju dengan mereka bahwa fitur ini harus ditutup. Saya pikir itu harus digabungkan (seperti yang ditunjukkan oleh komentar saya dan kotak centang yang ditandai di atas).

Saya setuju dengan @withoutboats bahwa kita tidak boleh menambahkan alat baru yang tidak dikenal yang tidak dimotivasi oleh kasus penggunaan yang spesifik dan penting. Saya pikir fitur ini akan terasa familier dan dimotivasi oleh kasus penggunaan yang spesifik dan penting.

@tanpa perahu

Saya merasa agak tidak adil bagi saya untuk menyetujui eksperimen ini; sulit untuk membuktikan yang negatif tetapi saya tidak tahu contoh kode seperti apa yang dapat mengatasi penentangan saya untuk menambahkan bentuk aliran kontrol ini ke bahasa.

Saya tidak berpikir bilah yang kami tetapkan adalah "tunjukkan kepada kami bahwa tidak ada kode yang bisa lebih baik ditulis dengan label-break-value"-- itu "tunjukkan kepada kami bahwa kode spesifik yang kami inginkan untuk label-break-value dapat menjadi lebih jelas ditulis dengan cara lain." Percakapan ini dimulai ketika Anda dan orang lain meminta contoh motivasi tentang manfaat fitur ini, dan banyak orang di utas ini (termasuk saya) telah memberikan contoh. Mereka tidak meyakinkan Anda atau @joshtriplett , jadi saya sekarang bertanya bagaimana Anda berdua akan menulis contoh-contoh ini tanpa label-break-value. Apakah Anda setuju bahwa contoh lebih baik ditulis menggunakan label-break-value? Jika demikian, apakah posisi Anda bahwa mereka tidak cukup umum untuk melebihi biaya mengizinkan pengguna untuk menulis kode break-to-block yang berpotensi rumit?

Saya akan maju dan berani di sini:

@rfcbot batal

@scottmcm proposal dibatalkan.

Hal ini sangat tidak teratur untuk istirahat untuk keluar dari blok hanya jika mereka diberi label, ketika pecah dari loop yang tidak berlabel.

Tidak yakin apakah itu disebutkan di utas atau tidak, tetapi blok yang tidak dapat ditargetkan oleh break; membuat blok berlabel secara kualitatif lebih kuat daripada berlabel loop dalam beberapa hal.

Dengan blok berlabel, Anda dapat membuat makro aliran kontrol yang mendukung break; di dalamnya, dengan infra makro yang sepenuhnya tidak terlihat oleh pengguna.
Dengan loop berlabel selalu ada risiko bahwa break; label akan digunakan dan akan ditangkap oleh infra makro daripada oleh target yang diinginkan.

Dalam prototipe EXPR is PAT saya, saya menggunakan loop s biasa untuk desugaring pada awalnya, tetapi semuanya rusak karena masalah yang disebutkan di atas, saya tidak dapat mem-bootstrap kompiler secara khusus.
Blok berlabel tidak diterapkan saat itu, jadi saya harus memperkenalkan " loop " khusus yang tidak dapat ditargetkan ke dalam AST dan menggunakannya dalam desugaring.

Seperti yang ditunjukkan oleh kotak centang saya, saya mendukung menstabilkan ini sekarang. Saya pikir ini adalah perpanjangan alami dari bahasa yang memfasilitasi makro serta aliran kontrol yang tidak begitu sesuai dengan pola fungsional. Meskipun NLL membuat masa hidup menjadi non-leksikal, saya pikir kemampuan untuk membubuhi keterangan blok dengan masa hidup juga menurut saya sangat membantu secara pedagogis seperti halnya tipe ascription.

Namun, karena konsensus sulit dicapai, untuk kepentingan menemukannya, saya menyarankan agar kami mencoba mempercepat pengerjaan try { ... } serta mempercepat pengerjaan eksperimen dengan https://github.com /rust-lang/rust/issues/53667 (atau bersamaan dengan sintaks EXPR is PAT @petrochenkov ).

Maaf, apa statusnya sekarang? Apakah kita di FCP atau tidak?

@mark-im Karena tidak ada label proposed-final-comment-period atau final-comment-period yang dipermasalahkan, kami tidak berada dalam FCP atau proposal untuk label tersebut.

(dan kami belum pernah di FCP, meskipun ada proposal awal untuk masuk FCP dengan semua kecuali tiga kotak dicentang)

@scottmcm

Saya akan maju dan berani di sini:

Pengulangan kata-kata @joshtriplett ini saya baca sebagai sangat sarkastis. Sebagai anggota tim lang, harap berhati-hati dalam berkomunikasi dengan kontributor lain.

Saya yakin bahwa ini sebenarnya adalah ide yang bagus. Saya sudah sangat anti fitur ini sebelumnya, dan saya masih berpikir ini adalah fitur yang tidak boleh digunakan oleh programmer. Kasus penggunaan di atas agak persuasif, tetapi saya pikir mereka mungkin masih lebih baik diperhitungkan dalam fungsi yang lebih kecil. Kasus yang saya temukan benar-benar persuasif adalah sebagai output dari makro. Jika pengguna dapat memasukkan return entah bagaimana, maka ini menghalangi penerjemahan ke dalam fungsi. Namun, yang sebenarnya kami inginkan hanyalah goto . Saya ingin tahu apakah solusi 'besar' adalah makro yang dapat menampilkan HIR, bukan token, tetapi itu sedikit di luar sana. Sementara itu, akan menyenangkan untuk memiliki fitur ini untuk penulis makro, jadi pada keseimbangan saya pikir kita harus menstabilkan.

Adakah yang mencoba menulis ulang hal-hal dengan cara yang lebih lambat, kurang intuitif, dan kurang ergonomis?

Memecah balok itu seperti goto yang ergonomis. Ini hampir tidak memiliki masalah goto, tetapi sama kuatnya.

Berdasarkan perubahan hati @nrc , saya bergerak, sekali lagi, untuk menstabilkan label_break_value .
Laporan saya dapat ditemukan di https://github.com/rust-lang/rust/issues/48594#issuecomment -421625182.

@rfcbot gabung
@rfcbot mengkhawatirkan FIXME-in-tests

Untuk memastikan bahwa @joshtriplett dan @withoutboats punya waktu untuk

@rfcbot prihatin memberi-perahu-dan-josh-waktu-untuk-meningkatkan-setiap-kekhawatiran-mereka-mungkin-masih-memiliki

Sebagai catatan proses untuk masalah ini dan untuk semua yang lain, harap hindari membatalkan proposal bolak-balik... jika Anda tidak berpikir sesuatu harus bergerak maju, gunakan saja kekhawatiran untuk itu.

Anggota tim @Centril telah mengusulkan untuk menggabungkan ini. Langkah selanjutnya adalah peninjauan oleh anggota tim yang ditandai lainnya:

  • [x] @Centril
  • [x] @aturon
  • [x] @cramertj
  • [x] @eddyb
  • [x] @joshtriplett
  • [ ] @nikomatsakis
  • [ ] @nrc
  • [x] @pnkfelix
  • [ ] @scottmcm
  • [ ] @tanpa perahu

Kekhawatiran:

Setelah mayoritas peninjau menyetujui (dan paling banyak 2 persetujuan belum diselesaikan), ini akan memasuki periode komentar terakhirnya. Jika Anda menemukan masalah besar yang belum diangkat pada titik mana pun dalam proses ini, silakan angkat bicara!

Lihat dokumen ini untuk info tentang perintah apa yang dapat diberikan oleh anggota tim yang ditandai kepada saya.

@rfcbot mengkhawatirkan pemblokiran

Saya sudah menyatakan posisi saya, yaitu Rust seharusnya tidak memiliki fitur ini. Saya ragu ini akan menjadi prioritas yang cukup tinggi untuk proyek sehingga saya dapat mencurahkan waktu untuk terlibat dalam proses mencapai konsensus pada proposal ini kapan saja dalam waktu dekat.

@rfcbot menyelesaikan memberi-perahu-dan-josh-waktu-untuk-meningkatkan-setiap-masalah-mereka-mungkin-masih-memiliki

Jika memang penting: Zig juga memiliki fitur ini .

Pada 5 Januari 2019 9:18:29 PST, Mazdak Farrokhzad [email protected] menulis:

@rfcbot menyelesaikan
beri-perahu-dan-josh-waktu-untuk-meningkatkan-kekhawatiran-mereka-mungkin-masih-memiliki

Kami sudah menyampaikan kekhawatiran, dan itu sama dengan "ini tidak boleh dalam bahasa". Kekhawatiran itu tidak akan hilang.

Saya lebih suka gagasan nrc bahwa makro harus dapat menghasilkan IR. Itu sepertinya solusi yang sepenuhnya masuk akal untuk ini dan banyak kemungkinan di masa depan, tanpa harus menambahkan sintaksis permukaan bahasa.

@joshtriplett

Kami sudah menyampaikan kekhawatiran, dan itu sama dengan "ini tidak boleh dalam bahasa". Kekhawatiran itu tidak akan hilang.

Untuk memperjelas maksud saya mendaftarkan mereka dengan @rfcbot karena bot tidak akan melihat masalah lama terdaftar setelah proposal dibatalkan. Saya menyampaikan kekhawatiran itu karena saya tahu bahwa Anda memiliki kekhawatiran, sebagai rasa hormat kepada Anda.

Saya lebih suka gagasan nrc bahwa makro harus dapat menghasilkan IR. Itu sepertinya solusi yang sepenuhnya masuk akal untuk ini dan banyak kemungkinan di masa depan, tanpa harus menambahkan sintaksis permukaan bahasa.

Saya tidak tahu seperti apa bentuknya atau itu ide yang lebih baik; tampaknya agak spekulatif (dalam arti "ini mungkin memakan waktu bertahun-tahun sebelum desain bahkan disetujui") dan lebih mahal daripada solusi berbiaya rendah break 'label expr yang juga memiliki manfaat di luar hasil makro ekspansi.

_Sebagai catatan proses untuk masalah ini dan untuk semua masalah lainnya, harap hindari membatalkan proposal bolak-balik... jika menurut Anda tidak ada yang harus dilanjutkan, cukup gunakan kekhawatiran untuk itu._

Saya tentu setuju dengan itu. Namun, saya tidak berpikir bahwa yang menjadi perhatian adalah mekanisme yang tepat di sini. Kekhawatiran sepertinya "jika ini diselesaikan maka saya akan menyetujui". Di sini, masalahnya adalah "ini tidak boleh maju sama sekali, 'gabung' adalah target yang salah, saya ingin 'menutup' sebagai gantinya". Itu sepertinya tidak ditangani dengan baik oleh mekanisme "keprihatinan".

@joshtriplett Sebagai tempat menarik, bisakah Anda mengarahkan saya ke masalah yang diangkat yang Anda sebutkan sebelumnya? Saya telah membaca utas RFC asli dan tidak yakin apa yang dirujuk secara khusus. Terima kasih.

@rfcbot menyangkut ergonomi dan pengoptimalan/kinerja (contoh non-karat dari penurunan kinerja dan ergonomi https://Gist.github.com/SoniEx2/fc5d3614614e4e3fe131#file-special-lua )

idk jika saya menggunakan ini dengan benar

(perhatikan bagaimana beberapa "desugaring" (sebenarnya saya akan mengatakan itu kebalikan dari desugaring - goto adalah primitif, loop desugar menjadi goto) cukup mengerikan)

(perhatikan juga bahwa lua tidak memiliki label apa pun sehingga memaksa Anda untuk menggunakan goto. meskipun demikian, saya yakin setidaknya satu break-block masih diperlukan, tetapi mungkin dengan "desugaring" yang lebih bersih.)

@rfcbot perhatian harus-tutup-tidak-gabung

(Seperti yang disarankan oleh @centril di Discord.)

Saya tidak yakin apakah ini adalah argumen yang mendukung stabilisasi atau menentang, tetapi perhatikan bahwa ini mudah untuk dikodekan dalam Rust stabil hari ini:

fn main() {
    'foo: for _ in 0..1 {
        println!("break");
        break 'foo;
        println!("broken");
    }
}

Jadi di satu sisi, kita harus menstabilkan ini karena hampir tidak mengembangkan bahasa, hanya menghindari for _ in 0..1 , di sisi lain kita tidak boleh menstabilkan ini karena ada cara mudah untuk melakukannya hari ini (untuk saat itu benar-benar diperlukan) dan kita tidak boleh mendorong penggunaan anti-pola seperti itu.

sepertinya agak membingungkan dan labelnya tidak perlu.

memecahkan balok jauh lebih tidak membingungkan dan membutuhkan label.

Saya tidak mengerti mengapa menurut Anda memecahkan balok adalah anti-pola. apa yang berlaku untuk X belum tentu berlaku untuk yang tidak terlalu X. Saya mungkin bisa membeli komputer seharga $299,99, tapi bukan $299,98, meskipun "pada dasarnya" sama.

@nrc

Saya tidak yakin apakah ini adalah argumen yang mendukung stabilisasi atau menentang, tetapi perhatikan bahwa ini mudah untuk dikodekan dalam Rust stabil hari ini:

    'foo: for _ in 0..1 {
        break 'foo;
    }

Jadi di satu sisi, kita harus menstabilkan ini karena hampir tidak mengembangkan bahasa, hanya menghindari for _ in 0..1 ,

'a: for _ in 0..1 { break 'a } mungkin berhasil jika tujuan eksplisitnya adalah agar tidak ada orang yang pernah menulis 'a: { ... break 'a e; ... } ; namun, ia memiliki kelemahan dalam menghasilkan IR sampah yang harus diproses oleh pemeriksa tipe, MIR, dan LLVM sehingga memperburuk waktu kompilasi (setidaknya dibandingkan dengan LBV).

di sisi lain kita tidak boleh menstabilkan ini karena ada cara mudah untuk melakukannya hari ini (untuk saat itu benar-benar diperlukan) dan kita tidak boleh mendorong penggunaan anti-pola seperti itu.

Saya pikir kami tidak setuju bahwa LBV adalah anti-pola. Pada akhirnya kami memilih untuk mengilhami Rust dengan aliran kontrol imperatif daripada hanya menjadikan Rust sebagai bahasa pemrograman fungsional. Meskipun saya mungkin lebih suka untuk tidak memiliki aliran kontrol seperti itu, itu fait accompli. Pertanyaannya adalah apakah LBV entah bagaimana lebih tidak terbaca atau bermasalah daripada mekanisme imperatif lainnya di Rust. Saya tidak berpikir itu.

Sementara saya berpikir bahwa fungsi harus tetap pendek (vertikal) dan dangkal (lekukan), lebih baik panjang dan dangkal daripada panjang dan dalam. Saya menemukan bahwa LBV membantu menghindari kedalaman di beberapa aliran yang lebih rumit. LBV juga tampaknya dapat dibaca oleh saya karena secara eksplisit menunjukkan ke mana ia akan melompat, membuat alurnya dipahami dengan baik. Secara keseluruhan, saya menemukan LBV sebagai salah satu aliran kontrol imperatif yang paling tidak bermasalah.

  1. 'a: for _ in 0..1 { break 'a }
  2. 'a: { ... break 'a e; ... }

ini mungkin terlihat mirip, tetapi mereka tidak persis sama. sedangkan yang pertama bisa dibilang anti-pola, yang kedua bisa dibilang tidak.

agak seperti loop {} vs while true {} (diberikan loop dapat mengembalikan nilai sementara while tidak bisa, tapi mari kita abaikan itu sebentar)

@nrc Itu tidak memiliki perilaku yang sama: https://github.com/rust-lang/rust/issues/48594#issuecomment -450246249

Secara khusus, perilaku break; dan continue; berbeda. Pertimbangkan kode hipotetis ini:

some_macro! {
   ...
   break;
   ...
}

Jika some_macro diperluas ke 'a { ... } , itu memiliki perilaku yang berbeda dari jika diperluas ke 'a: for _ 0..1 { ... }

@SoniEx2

Adakah yang mencoba menulis ulang hal-hal dengan cara yang lebih lambat, kurang intuitif, dan kurang ergonomis?

Silakan coba untuk berkomunikasi kekhawatiran Anda dalam cara yang lebih positif dan produktif. Mengejek orang lain tidak membawa kita kemana-mana, dan membuat orang merasa buruk. Kami semua ada di sini karena kami ingin memastikan bahwa Rust adalah bahasa pemrograman terbaik, dan bagian dari proses itu adalah memastikan bahwa komunitasnya sepositif dan semenyenangkan mungkin.

Mungkin aku jatuh dari beberapa kesalahpahaman besar. Saya tidak akan berpura-pura menjadi ahli dalam LLVM, internal Rust, atau hal serupa lainnya. Yang mengatakan, saya memiliki beberapa pengalaman dasar dengan desain kompiler dan saya bingung tentang apa yang menjadi perhatiannya. Jika seseorang dapat menjelaskan banyak hal, saya akan sangat menghargainya.

Cara saya melihat sesuatu:

1) Ini tidak mengubah ergonomi kontrol aliran. Sudah ada konstruksi seperti ini di Rust seperti 'a: loop { if x { break 'a; } break; } .

2) Ini tidak secara khusus mengubah ergonomi pengembalian blok: loop sudah mampu mengembalikan nilai.

Bagi saya, ini lebih seperti penyelesaian intuitif dari serangkaian fitur yang sudah dimiliki Rust - menggeneralisasi fitur tersebut untuk semua (atau setidaknya lebih) blok.

Dalam hal kekhawatiran tentang ini terlalu mirip dengan goto , saya semakin bingung. Ini tidak menambahkan apa pun yang belum mungkin dilakukan di Rust, dan itu tidak mengizinkan lompatan mundur (masalah utama yang mengakibatkan penggunaan goto menjadi kode spageti), jadi saya gagal untuk memahami konsekuensi apa yang mungkin dimiliki fitur ini dalam codegen karena ini tampaknya hanya gula sintaksis untuk loop yang selalu putus.

Adakah yang bisa menjelaskan kepada saya dalam istilah yang lebih spesifik masalah apa yang ada?

Secara prosedural, IMO tidak pantas untuk mengajukan masalah concern blocking atau concern should-close-not-merge -style: masalah ini tidak mencantumkan masalah dengan fitur yang diusulkan atau apa pun yang dapat kami upayakan untuk diselesaikan- - itu hanya pemblokir permanen. Saya tidak berpikir bahwa mekanisme kekhawatiran rfcbot harus digunakan untuk fitur pemblokiran permanen, tetapi hanya untuk membantu melacak penyelesaian masalah dan memastikan bahwa mereka ditangani/diselesaikan dengan tepat. Pemahaman saya tentang prosesnya adalah bahwa maksudnya adalah menggunakan kotak centang yang tidak dicentang untuk menandai ketidaksetujuan Anda, dan kekhawatiran itu akan digunakan untuk mengajukan masalah spesifik yang dapat didiskusikan tentang fitur dan fungsinya.

Saya dapat mengajukan masalah serupa "Saya tidak suka ini" pada fitur lain yang secara pribadi tidak saya setujui (lihat misalnya uniform_paths), tetapi saya tidak percaya bahwa infinite-filibuster adalah cara yang produktif untuk melakukan desain bahasa.

Jika ada kekhawatiran khusus tentang cara fitur ini berinteraksi dengan bagian lain dari bahasa yang harus didiskusikan/diselesaikan (mis. "Sepertinya ini dapat dihindari dengan try { ... } " atau "ini membantu untuk mengaktifkan un- fungsi idiomatically-large") Saya pikir akan lebih produktif untuk mengajukannya seperti itu.

@cramertj Saya tidak akan mengajukan masalah seperti itu dalam formulir itu jika @Centril tidak secara eksplisit menyarankannya. (Saya pribadi lebih suka jika FCP tidak diusulkan.)

Apa yang akan Anda sarankan sebagai proses yang sesuai untuk "ini harus ditutup", jika seseorang telah mengajukan P-FCP dengan rfcbot untuk sesuatu selain "tutup"? "pastikan bahwa mereka ditangani / diselesaikan dengan tepat" terdengar setara dengan "ini akan stabil suatu hari, apa yang diperlukan untuk sampai ke sana?". Itu tidak meninggalkan jalur dalam aliran untuk "ini tidak boleh distabilkan, ini tidak boleh menjadi bagian dari bahasa".

Pemahaman saya tentang prosesnya adalah bahwa maksudnya adalah menggunakan kotak centang yang tidak dicentang untuk menandai ketidaksetujuan Anda

Kemudian kita perlu mengubah proses kembali untuk meminta semua kotak centang dicentang untuk melanjutkan.

Saya tidak percaya bahwa infinite-filibuster adalah cara yang produktif untuk melakukan desain bahasa.

Saya juga tidak percaya itu. Saya ingin menemukan jalan untuk menyimpulkan ini juga, saya hanya ingin melihatnya menyimpulkan ke arah yang berbeda.

Sebagai catatan, berdasarkan pengalaman dengan RFC ini, saya tidak berpikir itu ide yang baik untuk menanggapi RFC dengan peringatan "kita dapat mengevaluasi/mengatasi selama stabilisasi apakah kita harus melanjutkan", karena tampaknya jelas bagi saya bahwa melakukan hal itu menghasilkan masalah prosedural kritis seperti ini.

Kami membutuhkan jalan untuk mengatakan "ya, saya dapat melihat bagaimana fitur individu ini akan membuat bahasa lebih ekspresif, tetapi berdasarkan evaluasi keseluruhan bahasa, itu tidak membawa bobotnya, dan saya tidak ingin memperluas lebih lanjut luas permukaan bahasa dengan cara ini". Saya percaya kita perlu secara teratur membuat panggilan itu, jangan sampai setiap fitur yang diusulkan terlihat sebagai hal yang tak terhindarkan dalam beberapa bentuk dan hanya masalah memadamkan keberatan dan bertahan.

Saya akan mengulangi apa yang saya katakan sebelumnya karena tampaknya telah terjawab: https://github.com/rust-lang/rust/issues/48594#issuecomment -451795597

Saya pada dasarnya berbicara tentang perbedaan antara menggunakan loop dan menggunakan blok pemecah.

terutama, melanggar blok memiliki sintaks yang berbeda, (sedikit) semantik yang berbeda (sehubungan dengan istirahat berlabel setidaknya), mereka menandakan maksud yang berbeda, dan beberapa hal kecil lainnya.

apakah rfcbot mendukung anti-kekhawatiran?

@joshtriplett

Kami membutuhkan jalan untuk mengatakan "ya, saya dapat melihat bagaimana fitur individu ini akan membuat bahasa lebih ekspresif, tetapi berdasarkan evaluasi keseluruhan bahasa, itu tidak membawa bobotnya, dan saya tidak ingin memperluas lebih lanjut luas permukaan bahasa dengan cara ini". Saya percaya kita perlu secara teratur membuat panggilan itu, jangan sampai setiap fitur yang diusulkan terlihat sebagai hal yang tak terhindarkan dalam beberapa bentuk dan hanya masalah memadamkan keberatan dan bertahan.

Ya, ini adalah bahaya yang tidak menguntungkan dari proses kami saat ini yang menerima atau menolak fitur memerlukan konsensus penuh dari tim yang sesuai. Ketika tim lang sebesar sekarang, sulit untuk selalu mencapai ini-- Saya pikir dari komentar di atas bahwa ini hanya contoh kode yang hilang untuk memotivasi mengapa fitur ini penting, tetapi sekarang sepertinya Anda setuju bahwa ada adalah kode yang dapat ditulis dengan lebih baik menggunakan fitur ini, tetapi tidak yakin bahwa itu sepadan dengan biaya yang Anda lihat di sini. Saya tidak yakin cara untuk meyakinkan Anda bahwa kasus-kasus ini adalah motivasi yang cukup, karena sepertinya terus memberikan contoh (termasuk contoh makro, yang secara harfiah tidak mungkin untuk ditulis dalam gaya lain) tidak cukup.

Demikian pula, saya cukup yakin bahwa saya pribadi akan tetap yakin bahwa fitur ini harus digabungkan: IMO tidak hanya menarik bobotnya melalui berbagai contoh di mana itu adalah pilihan terbaik/satu-satunya, tetapi bahasanya sebenarnya lebih sederhana dengan penambahannya (karena tidak mengizinkan blok berlabel mengejutkan saya mengingat kami mengizinkan konstruksi berlabel lainnya).

Jika Anda setuju dengan ringkasan saya di atas tentang posisi Anda, maka tampaknya kita berada di jalan buntu yang tidak menguntungkan (dan, saya percaya, bersejarah!) karena kekurangan proses. Salah satu opsi adalah menafsirkan aturan rfcbot saat ini seperti yang saya lakukan di atas yang berarti "tidak ada kotak centang yang menandakan ketidaksetujuan Anda, tiga anggota diperlukan untuk mengesampingkan mayoritas", tetapi saya rasa aturan itu tidak dimaksudkan ketika diperkenalkan, jadi Saya pikir tidak jujur ​​jika saya menyarankan Anda untuk mengikuti prosedur ini (meskipun saya melakukannya sendiri di tempat lain).

Saya sebelumnya telah mendengar saran bahwa kami dapat memperkenalkan batas waktu untuk fitur dari yang disetujui->diimplementasikan->distabilkan, dan bahwa kami harus "menutup otomatis" fitur yang tertinggal dalam upaya untuk menghindari jaminan simpanan yang terus meningkat. Sesuatu seperti itu dapat mengatasi kasus ini, di mana saya (dan, saya pikir, beberapa orang lain dalam tim) tidak akan menandai kotak centang untuk ditutup, Anda juga tidak akan menandai kotak centang untuk menerima (bahkan sekarang saya masih merasa takut bahkan mengatakan ini bahwa saya' m membuang upaya terakhir untuk meyakinkan Anda! :senyum:).

Saya khawatir bahwa dengan tim yang terus berkembang, kita akan kehilangan kemampuan untuk mencapai konsensus tentang fitur, dan akan sulit untuk mengarahkan bahasa secara koheren, terutama pada tim desain-lang. Batas ukuran tim tampaknya merupakan solusi yang jelas untuk ini-- dimungkinkan untuk menerima masukan dari banyak orang, tetapi sangat tidak mungkin untuk membangun konsensus mutlak di antara kelompok yang cukup besar. Orang lain mungkin akan berpendapat bahwa fitur kontroversial tidak boleh digabungkan dalam upaya untuk melindungi bahasa dari kesalahan fitur. Saya pribadi berpikir komunitas tidak mungkin membiarkan kita melakukan banyak kesalahan itu tanpa peringatan yang memadai, tetapi ini adalah pemikiran.

Saya akan mencoba dan memulai utas terpisah untuk membahas evolusi proses di sini, dan sementara itu saya akan meminta orang-orang yang mengikuti utas ini, harap hanya memposting jika ada kasus penggunaan baru yang kritis untuk dipertimbangkan yang sangat berbeda dari yang disebutkan di atas, atau jika ada alasan signifikan yang belum dipertimbangkan mengapa fitur ini tidak boleh ditambahkan ke bahasa. Membaca seluruh sejarah pada megathreads ini sulit, tetapi menjadi lebih-lebih ketika posting diulang-ulang, atau ketika thread diisi dengan komentar yang tidak membantu. (katanya sekarang mengetik salah satu komentar terpanjang di seluruh utas XD)

TL; DR: Saya pikir kita terjebak, kita harus memiliki proses untuk ini-- Saya akan memulai percakapan itu di tempat lain dan menautkannya di sini. Jika tidak, jangan berkomentar kecuali Anda memiliki informasi baru yang signifikan yang perlu dipertimbangkan.

@cramertj

ini adalah bahaya yang tidak menguntungkan dari proses kami saat ini yang menerima atau menolak fitur memerlukan konsensus penuh dari tim yang sesuai

Sejujurnya saya akan menganggap itu sebagai fitur.

Saya pikir dari komentar di atas bahwa ini hanya contoh kode yang hilang untuk memotivasi mengapa fitur ini penting, tetapi sekarang sepertinya Anda setuju bahwa ada kode yang dapat ditulis lebih baik menggunakan fitur ini, tetapi tidak yakin bahwa itu layak biaya yang Anda lihat di sini.

Saya masih merasa bahwa banyak contoh dapat ditulis dengan cara lain. Ini tidak menambah ekspresi yang tidak dapat direpresentasikan ke dalam bahasa. Awalnya saya merasa bahwa itu dapat dimotivasi dengan contoh yang memadai, tetapi semakin banyak contoh yang saya lihat yang dapat menggunakan fitur ini, semakin saya setuju dengan @withoutboats bahwa fitur ini tidak boleh masuk ke dalam bahasa.

(Juga perlu diperhatikan: peti @nrc proc-macro-rules yang digunakan label_break_value tampaknya telah ditulis ulang untuk menghindarinya.)

Salah satu opsi adalah menafsirkan aturan rfcbot saat ini seperti yang saya lakukan di atas yang berarti "tidak ada kotak centang yang menandakan ketidaksetujuan Anda, tiga anggota diperlukan untuk mengesampingkan mayoritas", tetapi saya rasa aturan itu tidak dimaksudkan ketika diperkenalkan, jadi Saya pikir tidak jujur ​​jika saya menyarankan Anda untuk mengikuti prosedur ini (meskipun saya melakukannya sendiri di tempat lain).

Saya pikir itu prosedur yang benar untuk "abstain", tetapi tidak untuk keberatan.

IMO tidak hanya menarik bobotnya melalui berbagai contoh di mana itu adalah pilihan terbaik/satu-satunya, tetapi bahasanya sebenarnya lebih sederhana dengan penambahannya (karena tidak mengizinkan blok berlabel mengejutkan saya mengingat kami mengizinkan konstruksi berlabel lainnya).

Saya biasanya menemukan argumen ortogonalitas yang menarik, tetapi yang satu ini secara khusus menurut saya tidak menarik, karena secara pribadi saya lebih suka untuk tidak memberi label jeda loop dalam bahasa tersebut.

Saya khawatir bahwa dengan tim yang terus berkembang, kita akan kehilangan kemampuan untuk mencapai konsensus tentang fitur, dan akan sulit untuk mengarahkan bahasa secara koheren, terutama pada tim desain-lang.

Saya khawatir bukan hanya tentang kemudi tetapi tentang berhenti . Ada keniscayaan tertentu yang terkadang muncul, di mana prosesnya tampaknya terfokus pada menemukan jalur ke "ya" dan tidak ada tepi grafik di diagram alur yang mengarah ke "tidak", hanya "belum".

Ada banyak posting yang ditulis pada tahun 2018 dan 2019 berbicara tentang pertumbuhan fitur dalam bahasa, dan saya merasa bahwa dalam tim bahasa kita perlu memberikan pertimbangan serius terhadap total luas permukaan bahasa. Dan saya merasa kita tidak memiliki proses yang baik yang mendorong kita untuk melakukan itu.

@joshtriplett

Ini tidak menambah ekspresi yang tidak dapat direpresentasikan ke dalam bahasa.

Untuk menjadi sangat jelas: itu melakukan hal ini. Saat ini tidak ada cara untuk mengekspresikan kode ini yang tidak mengganggu konstruksi aliran kontrol lainnya, yang (seperti yang telah ditunjukkan orang lain) sangat diinginkan dalam makro, di mana ini akan menjadi satu-satunya konstruksi yang tidak dapat ditargetkan melalui jeda yang tidak berlabel, memungkinkan penulis makro untuk keluar dari bagian tanpa mengambil risiko tumpang tindih dengan break disediakan pengguna.

itu juga membuat kode lebih mudah dibaca karena Anda tidak perlu berzig-zag (jika kami tidak memiliki label sama sekali - lihat contoh Lua) atau melakukan hal-hal aneh dengan loop. ini juga memiliki manfaat kinerja yang kecil bahkan llvm harus dapat mengoptimalkan kode zigzag.

@joshtriplett

Saya masih merasa bahwa banyak contoh _bisa_ ditulis dengan cara lain. Ini tidak menambah ekspresi yang tidak dapat direpresentasikan ke dalam bahasa. Awalnya saya merasa bahwa itu dapat dimotivasi dengan contoh yang cukup, tetapi semakin banyak contoh yang saya lihat bahwa _dapat_ menggunakan fitur ini, semakin saya setuju dengan @withoutboats bahwa fitur ini tidak boleh digunakan dalam bahasa.

Apakah itu sesuatu yang mungkin bisa kita gali?

Saya biasanya menemukan argumen ortogonalitas yang menarik, tetapi yang satu ini secara khusus menurut saya tidak menarik, karena secara pribadi saya lebih suka untuk tidak memberi label jeda loop dalam bahasa tersebut.

Baris alasan ini menurut saya aneh (kecuali jika Anda ingin menghapus jeda loop berlabel dengan edisi). Tampaknya tidak tepat untuk mendasarkan keputusan desain berdasarkan apa yang Anda harapkan tidak ada dalam bahasa tersebut. Itu ada di sana, jadi kita harus mempertimbangkan apakah penambahan ini koheren dengan itu. Kalau tidak, ada banyak hal yang mungkin saya lakukan secara berbeda tentang Rust, tetapi saya tidak boleh dan tidak bisa.

Saya khawatir bukan hanya tentang kemudi tetapi tentang _stopping_. Ada keniscayaan tertentu yang terkadang muncul, di mana prosesnya tampaknya terfokus pada menemukan jalur ke "ya" dan tidak ada tepi grafik di diagram alur yang mengarah ke "tidak", hanya "belum".

Belum adalah bentuk "tidak" dalam artian tidak akan stabil tanpa ya. Selanjutnya, ada yang tidak: meyakinkan kita semua bahwa LBV adalah ide yang buruk / tidak cukup termotivasi untuk alasan X, Y, dan Z. Saya belum pernah mendengar banyak argumen konkret seperti itu sama sekali. Anda juga telah menunjukkan dengan jelas di sini bahwa tidak ada keniscayaan.

Ada banyak posting yang ditulis pada tahun 2018 dan 2019 berbicara tentang pertumbuhan fitur dalam bahasa, dan saya merasa bahwa dalam tim bahasa kita perlu memberikan pertimbangan _serius_ untuk total luas permukaan bahasa. Dan saya merasa kita tidak memiliki proses yang baik yang mendorong kita untuk melakukan itu.

Saya pribadi merasa bahwa banyak dari posting ini baik tentang keberlanjutan (tapi tidak tepat worded sebagai @nikomatsakis lakukan ...) atau yang banyak orang tidak mengerti bagaimana tim bahasa beroperasi (yaitu kita sudah lakukan memberikan pertimbangan serius untuk total luas permukaan). Sintaks permukaan total Rust mungkin benar-benar menyusut selama setahun terakhir, tidak tumbuh. LBV tidak meningkat secara signifikan dan argumen dapat dibuat bahwa itu benar-benar menyusutkan jumlah produksi dalam bahasa dan membuat sintaks lebih seragam.

Menggabungkan produksi tata bahasa saja tidak mengecilkan luas permukaan bahasa.

Mengurangi jumlah cabang bersyarat yang dapat diambil seseorang bisa dibilang mengecilkan luas permukaan bahasa.

Saya tidak berpikir fitur khusus ini berjalan baik, karena itu mungkin netral. Tapi misalnya hal-hal yang menyatukan konstruksi bahasa (bool let, siapa?) melakukan mengecilkan luas permukaan.

Untuk apa nilainya, Common Lisp, yang mirip dengan Rust dalam arti bahwa itu adalah bahasa multi-paradigma dengan makro, memiliki fitur ini (bernama block / return-from ). Mirip dengan apa yang telah dibahas di sini, di Common Lisp konstruksi ini sering membantu saat menulis makro dan dalam mengekspresikan aliran kontrol yang kompleks dan tidak dapat direduksi.

(block foo
  (return-from foo "value"))

Perasaan saya adalah bahwa di Common Lisp fitur ini dianggap berhasil. Itu tidak muncul dalam percakapan tentang fitur yang membuat bahasa sulit dipelajari atau diterapkan.

Ada penyertaan

early return from block ⊂ exceptions ⊂ call/cc

Misalnya, dalam Skema, emulasi return-from ini layak dilakukan:

(define call/cc call-with-current-continuation)

(define-syntax block
    (syntax-rules ()
        ((_ label statements ...)
            (call/cc (lambda (label) (begin statements ...))))))

(block foo
    (display "Visible text")
    (foo "value")
    (display "Phantom text"))

Dalam Skema, call/cc dianggap sukses dan kontroversial. Saya menemukan ini sangat menarik karena Anda harus terlebih dahulu merumuskan objek untuk dapat membicarakannya. Bahkan jika Anda menganggap call/cc sebagai kesalahan, itu membuat bahasa lebih substansial dalam arti intelektual.

Bahasa Nemerle memiliki fungsionalitas blok bernama .
Ini sangat berguna dan nyaman.

return, break, dan continue diimplementasikan sebagai makro menggunakan fitur ini.

@jhpratt Silakan baca pembahasan di soal.

Mengulangi beberapa komentar yang saya buat di IRLO atas saran @Centril :

Dalam membahas fitur ini, saya menyarankan inspirasi berikut (berlawanan dengan versi terkait loop biasa):

Loop sebenarnya bukan inspirasi saya di sini. Ketika saya melihat blok try, saya pikir "man, akan berguna untuk dapat menulis beberapa perhitungan lokal singkat dengan pengembalian awal tanpa harus repot membuat penutupan". coba blok berfungsi untuk "Saya ingin mengembalikan coba impl" yang agak terbatas, dan tidak mendukung label apa pun.

Di atas adalah kasus penggunaan utama saya untuk ini: Saya suka gaya pengembalian awal. try {} blok membuat kita lebih sering ke sana, tetapi, sekali lagi, mereka tidak benar-benar mendukung label (bukan itu yang Anda perlukan, karena Anda akan menulis try {}? untuk blok bersarang) dan membuat Anda memasukkan tipe Anda ke dalam bentuk monadik tertentu yang tidak menarik (sebagaimana dibuktikan oleh kasus penggunaan yang disediakan).

Saya juga membuat beberapa pengamatan tentang C++, di mana tidak memiliki label break/continue sangat menyakitkan, terutama karena tidak adanya iterator seperti Rust. Misalnya, tidak ada cara untuk melanjutkan loop luar dari loop dalam tanpa kemungkinan-UB goto atau break ditambah continue bersyarat di luar loop dalam.

Setidaknya C ++ 's kurangnya pinjam-checker membuat inline lambda trik kurang menyakitkan, yang tidak, efektif, dukungan LVB, sejak kembali di lambda inline akan berubah menjadi sesuatu seperti LVB oleh inliner LLVM ini. Sesuatu seperti ini... sedikit lebih dipertanyakan di Rust.

Saya juga harus menunjukkan bahwa fitur ini kira-kira setara dalam ekspresif dengan Go goto , yang memaksa waktu kompilasi untuk tidak melompati deklarasi dan yang lainnya (terus terang, jika Rob Pike berpikir goto dapat diterima, mengingat sejarah mencoba mengatasi masalah C++, saya agak percaya padanya tentang itu).

Selain itu, jika kita akan membahas prior art, Kotlin juga menyediakan fitur persis ini, dalam bentuk return<strong i="24">@label</strong> expr; .

Dalam bahasa c'ish saya sering menggunakan label, bahkan tanpa goto masuk, sebagai lokasi untuk breakpoint stabil di bawah loop, karena debugger dapat mengenali break function:label .
Bahkan tanpa konsensus tentang istirahat, label mungkin bagus.

Sunting: Salah satu rintangan potensial, adalah bahwa biasanya label mengikuti konvensi penamaan simbol, jika saya memahami RFC, label ini tidak mengikuti konvensi penamaan simbol di mana ', tidak valid dalam nama simbol.
Saya tidak yakin begitu saja misalnya Dwarf, atau gdb sendiri jika sebenarnya ada masalah di sini.

Sunting2:
Cukup yakin ada beberapa asap untuk ini, jika kita melihat perilaku mengutip label berbasis c normal,
di debugger, gdb setidaknya akan memperlakukan tanda kutip, untuk mengutip daripada bagian dari nama simbol. Hasil berikut di

Breakpoint 1 pada 0x401114: file, baris 1.
kutipan yang tak tertandingi

echo "void main() { } void hmm() { umm: return; }" | gcc -g -x c -;
gdb -ex "b hmm:'umm'" -ex "b hmm:'umm" -batch ./a.out

Dan saya tidak percaya ini dapat dipengaruhi oleh dukungan khusus bahasa bahasa karat di gdb, karena saya percaya kutipan ini terjadi sebelum pencocokan simbol.

Sunting: Kapal mungkin berlayar dengan ini karena label loop yang ada.

Poin kecil yang mendukung pengembalian awal dari blok adalah pemrograman kontrak orang miskin. Seseorang cukup menambahkan pernyataan tegas sebagai pra dan pascakondisi. Untuk menjaga kenyamanan, mungkin untuk mengganti return dengan break 'ret untuk mengizinkan konstruksi ini:

let value = 'ret: {
    // ...
};
assert!(postcondition(value));
return value;

Namun, ini adalah solusi yang tidak sempurna, karena return harus dilarang di dalam blok.

Menambahkan catatan bahwa saya menginginkan fitur ini tetapi tidak menggunakannya karena saya tidak tahu itu ada, yang saya rasa adalah pengubah negatif pada "orang tidak menginginkannya terbukti dengan sedikit orang yang menggunakannya".

Saya secara mandiri menemukan kembali konsep di IRLO pagi ini .

Saya telah bermain-main dengan ini hari ini, dan itu _super_ berguna dalam blok async . Namun, tampaknya mengalami masalah saat digabungkan dengan fitur try_blocks :

#![feature(try_blocks, label_break_value)]

fn main() {
    let _: Result<(), ()> = try {
        'foo: {
            Err(())?;
            break 'foo;
        }
    };
}
error[E0695]: unlabeled `break` inside of a labeled block
 --> src/main.rs:6:20
  |
6 |             Err(())?;
  |                    ^ `break` statements that would diverge to or through a labeled block need to bear a label

error: aborting due to previous error

mencoba blok adalah kesalahan.

... tidak bisakah Anda memberi label pada ? itu sendiri? (seperti pada Err(()) 'foo?; )

Saya sangat tidak setuju bahwa blok percobaan adalah kesalahan, meskipun itu adalah diskusi terpisah, dan mungkin tidak layak untuk bolak-balik di sini.

Dalam contoh khusus ini mungkin bisa dilakukan, tetapi ini sangat diminimalkan dibandingkan dengan kode asli yang saya miliki, di mana 'foo berisi potongan kode yang layak, dan beberapa ? s.

@SoniEx2

mencoba blok adalah kesalahan.

Komentar ini tidak pantas. Komentar @jonhoo melaporkan interaksi kereta (mungkin). Terlepas dari pendapat seseorang tentang blok try (atau label-break-value) jelas bahwa mereka harus beroperasi dengan lancar.

seharusnya, dengan sintaks Err(()) 'foo?; .

@jonhoo Saya menduga Anda melihat detail impl bocor dalam hal bagaimana try didesugasi -- dapatkah Anda mengajukannya sebagai masalah terpisah dan kami dapat memindahkan diskusi tentang kemungkinan perbaikan di sana?

RFC mengatakan bahwa

'BLOCK_LABEL: { EXPR }

adalah gula sintaksis untuk

'BLOCK_LABEL: loop { break { EXPR } }

Saya mencoba membuat substitusi itu, dan kode dikompilasi, dengan peringatan tentang kode yang tidak dapat dijangkau.

#![feature(try_blocks, label_break_value)]

fn main() {
    let _: Result<(), ()> = try {
        'foo: loop {
            break {
                Err(())?;
                break 'foo;
            }
        }
    };
}

@nikomatsakis @ciphergoth diajukan sebagai https://github.com/rust-lang/rust/issues/72483.

Saya menemukan bahwa saya tidak lagi keberatan dengan ini. Saya akan lebih keberatan dengan konsep awal istirahat berlabel jika itu untuk dipertimbangkan hari ini, tetapi mengingat bahwa konsep itu ada, saya tidak berpikir masuk akal bagi saya untuk terus menolak penerapannya pada blok arbitrer.

(Ini berlaku untuk formulir saat ini, menggunakan break , bukan untuk sintaks lainnya.)

@rfcbot menyelesaikan harus-menutup-tidak-menggabungkan
@rfcbot ditinjau

@joshtriplett Untuk apa nilainya, saya menemukan ini sangat berguna di blok async , karena itu satu-satunya cara untuk melakukan "pengembalian lebih awal". Ini berarti bahwa alih-alih menulis:

async {
  // do thing a
  if thing_a_failed {
    // handle specially (note, _not_ ?)
  } else {
    // do thing b
    if thing_b_failed {
      // handle specially (note, _not_ ?)
    } else {
      // do thing c, etc..
    }
  }
}

Saya bisa menulis:

async {
  'block {
  // do thing a
  if thing_a_failed {
    // handle specially (note, _not_ ?)
    break 'block;
  }

  // do thing b
  if thing_b_failed {
    // handle specially (note, _not_ ?)
    break 'block;
  }

  // do thing c, etc..
  }
}

Ini sangat analog dengan bagaimana Anda dapat kembali lebih awal dengan return dalam fungsi/penutupan, dan dengan continue/break dalam loop. Memang akan lebih baik jika saya tidak membutuhkan blok tambahan ( async 'block { kemungkinan?), tapi itu pasti mengalahkan if-s bersarang.

Mengizinkan blok asinkron untuk dianotasi secara langsung dengan label terdengar seperti ekstensi yang sangat bagus untuk fitur ini.

@rfcbot fcp batal

Saya akan membatalkan FCP di sini karena telah diblokir selamanya. Kita mungkin harus mendiskusikan apakah kita ingin mendorong masa depan ini. Jika tidak ada yang lain, sepertinya itu harus diperbarui untuk memperhitungkan blok asinkron, dan sepertinya itu menambahkan kasus penggunaan baru untuk fitur tersebut.

Proposal @nikomatsaki dibatalkan.

Perhatikan bahwa tidak ada ambiguitas tentang semantik proposal ini dengan adanya blok asinkron: definisi dalam RFC masih berlaku yaitu

'BLOCK_LABEL: { EXPR }

hanyalah gula sintaksis untuk

'BLOCK_LABEL: loop { break { EXPR } }

kecuali bahwa pemutusan atau kelanjutan yang tidak berlabel yang akan mengikat ke loop implisit dilarang di dalam EXPR.

Perhatikan bahwa Anda dapat (awal) return dari blok asinkron, alih-alih berlabel break , jadi pelabelan blok asinkron tidak masuk akal:

let fut = async {
    return 42;
    0
};

println!("{}", fut.await); // prints 42

( taman bermain )

@WaffleLapkin Saya sebenarnya baru saja datang ke sini untuk mencatat bahwa karena saya baru-baru ini diberitahu tentang itu sendiri! Saya pikir fitur ini masih sangat berguna untuk dapat _melewati_ bagian kode (tidak menjalankan sisa blok ini, tetapi juga tidak kembali), tetapi penerapannya untuk async _khusus_ kurang dari Saya awalnya berpikir.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat