Apakah kelanjutan kelas satu berguna dalam bahasa pemrograman berorientasi objek modern?

10

Lanjutan sangat berguna dalam bahasa pemrograman fungsional (misalnya Contmonad di Haskell) karena memungkinkan notasi sederhana dan teratur untuk kode gaya imperatif. Mereka juga berguna dalam beberapa bahasa imperatif lama karena mereka dapat digunakan untuk mengimplementasikan fitur bahasa yang hilang (mis. Pengecualian, coroutine, utas hijau). Tetapi untuk bahasa berorientasi objek modern dengan dukungan yang dibangun untuk fitur-fitur ini, argumen apa yang akan ada untuk juga menambahkan dukungan untuk kelanjutan kelas satu (apakah gaya dibatasi lebih modern resetdan shiftatau seperti skema call-with-current-continuation)?

Apakah ada argumen yang menentang penambahan dukungan selain kinerja dan kompleksitas implementasi?

Jules
sumber

Jawaban:

15

Biarkan Eric Lippert yang menjawab ini:

Pertanyaan yang jelas pada saat ini adalah: jika CPS sangat mengagumkan lalu mengapa kita tidak menggunakannya sepanjang waktu? Mengapa sebagian besar pengembang profesional tidak pernah mendengarnya, atau, yang memiliki, menganggapnya sebagai sesuatu yang hanya dilakukan oleh programmer Skema gila itu?

Pertama-tama, sulit bagi kebanyakan orang yang terbiasa berpikir tentang subrutin, loop, try-catch-akhirnya dan seterusnya dengan alasan tentang delegasi yang digunakan untuk aliran kontrol dengan cara ini. Saya sedang meninjau catatan saya pada CPS dari CS442 sekarang dan saya melihat bahwa pada tahun 1995 saya menulis sebuah tulisan: "Dengan kelanjutan Anda harus menyortir berdiri di kepala Anda dan menarik diri Anda ke dalam". Profesor Duggan (*) benar sekali mengatakan itu. Ingat dari beberapa hari yang lalu bahwa contoh kecil kami dari transformasi CPS dari ekspresi C # M (B ()? C (): D ()) melibatkan empat lambda. Tidak semua orang pandai membaca kode yang menggunakan fungsi tingkat tinggi. Ini membebankan beban kognitif yang besar.

Selain itu: salah satu hal yang menyenangkan tentang pernyataan aliran kontrol spesifik yang dimasukkan ke dalam bahasa adalah bahwa mereka membiarkan kode Anda dengan jelas mengekspresikan makna aliran kontrol sambil menyembunyikan mekanisme - tumpukan panggilan dan alamat pengirim dan pengecualian daftar penangan dan wilayah yang dilindungi dan seterusnya. Kelanjutan membuat mekanisme aliran kontrol eksplisit dalam struktur kode. Semua penekanan pada mekanisme dapat membanjiri makna kode.

Dalam artikel selanjutnya , ia menjelaskan bagaimana sinkronisasi dan kelanjutan sama persis satu sama lain, dan menunjukkan demonstrasi mengambil operasi jaringan yang sederhana, tetapi memblokir, dan menulis ulang dalam gaya asinkron, memastikan untuk menutupi semua yang disembunyikan. Gotchas yang harus ditutup untuk memperbaikinya. Itu berubah menjadi besar berantakan kode. Ringkasannya di bagian akhir:

Ya ampun, betapa berantakan yang kami buat. Kami telah memperluas dua baris kode yang sangat jelas menjadi dua lusin baris spageti paling memabukkan yang pernah Anda lihat. Dan tentu saja itu masih tidak bisa dikompilasi karena label tidak dalam cakupan dan kami memiliki kesalahan tugas yang pasti. Kami masih harus menulis ulang kode lebih lanjut untuk memperbaiki masalah tersebut.

Ingat apa yang saya katakan tentang pro dan kontra CPS?

  • PRO: Aliran kontrol yang rumit dan menarik dapat dibangun dari bagian-bagian sederhana - periksa.
  • CON: Reifikasi aliran kontrol melalui kelanjutan sulit dibaca dan sulit untuk alasan tentang - periksa.
  • CON: Kode yang mewakili mekanisme aliran kontrol sepenuhnya melampaui makna kode - periksa.
  • CON: Transformasi aliran kontrol kode biasa ke CPS adalah jenis hal yang baik pada kompiler, dan hampir tidak ada orang lain - periksa.

Ini bukan latihan intelektual. Orang sungguhan akhirnya menulis kode yang secara moral setara dengan yang di atas sepanjang waktu ketika mereka berurusan dengan asinkron. Dan, ironisnya, bahkan ketika prosesor menjadi lebih cepat dan lebih murah, kita menghabiskan lebih banyak waktu kita menunggu hal-hal yang tidak terikat prosesor. Dalam banyak program, sebagian besar waktu yang dihabiskan adalah dengan prosesor yang dipatok ke nol menunggu paket jaringan untuk melakukan perjalanan dari Inggris ke Jepang dan kembali lagi, atau untuk disk berputar, atau apa pun.

Dan saya bahkan belum membicarakan apa yang terjadi jika Anda ingin membuat operasi asinkron lebih lanjut. Misalkan Anda ingin menjadikan ArchiveDocuments operasi asinkron yang membutuhkan delegasi. Sekarang semua kode yang memanggilnya harus ditulis dalam CPS juga. Noda itu menyebar begitu saja.

Melakukan logika asinkron dengan benar itu penting, itu hanya akan menjadi lebih penting di masa depan, dan alat-alat yang telah kami berikan membuat Anda “berdiri di atas kepala Anda dan mengubah diri Anda ke luar” seperti kata Profesor Duggan dengan bijak.

Gaya meneruskan kelanjutan sangat kuat, ya, tetapi harus ada cara yang lebih baik untuk memanfaatkan kekuatan itu dengan baik daripada kode di atas.

Kedua artikel, dan seri berikut tentang fitur bahasa C # baru yang memindahkan semua kekacauan ini ke kompiler dan memungkinkan Anda menulis kode Anda sebagai aliran kontrol normal dengan kata kunci khusus untuk menandai bagian-bagian tertentu sebagai asinkron, sangat layak dibaca bahkan jika Anda ' kembali bukan pengembang C #. Saya tidak, tapi itu masih pengalaman yang mencerahkan ketika saya bertemu untuk pertama kalinya.

Mason Wheeler
sumber
5
Perlu dicatat bahwa jika bahasa Anda mendukung ekstensi sintaksis seperti makro, maka kelanjutan menjadi jauh lebih berguna karena Anda dapat menyembunyikan mekanisme untuk menerapkan berbagai jenis aliran kontrol yang menarik di dalam ekstensi sintaksis. Yang pada dasarnya bagaimana "menunggu" bekerja, itu hanya didefinisikan dalam bahasa karena C # tidak menyediakan alat untuk menentukan jenis ekstensi sintaks sendiri.
Jack
Artikel bagus, walaupun saya akan mencatat bahwa CPS dan kelanjutan kelas satu tidak persis sama persis (CPS adalah apa yang Anda lakukan dalam bahasa tanpa dukungan untuk kelanjutan ketika Anda merasa Anda membutuhkannya). Kedengarannya seperti C # turun dengan rute yang sama persis dengan yang saya pikirkan (walaupun saya tidak dapat memutuskan apakah saya ingin mengotomatiskan transformasi ban ke CPS atau mengimplementasikan kelanjutan pembatasan terbatas penyalinan tumpukan salinan yang ditiru).
Jules
@ Jack - itulah yang sedang saya pertimbangkan saat ini: bahasa yang saya rancang memiliki fasilitas makro yang dapat mendukung transformasi CPS secara otomatis. Tetapi kelanjutan asli penuh mungkin memberikan kinerja yang lebih baik ... pertanyaannya adalah, seberapa sering mereka akan digunakan dalam situasi yang kritis terhadap kinerja?
Jules