Kembali dianggap berbahaya? Bisakah kode berfungsi tanpa itu?

45

OK, jadi judulnya sedikit clickbaity tapi serius saya sudah tahu, jangan minta tendangan untuk sementara waktu. Saya suka bagaimana ini mendorong metode untuk digunakan sebagai pesan dalam mode berorientasi objek yang benar. Tetapi ini memiliki masalah yang mengganggu yang telah mengoceh di kepala saya.

Saya curiga bahwa kode yang ditulis dengan baik dapat mengikuti prinsip-prinsip OO dan prinsip-prinsip fungsional secara bersamaan. Saya mencoba mendamaikan ide-ide ini dan poin penting yang saya dapatkan adalah return.

Fungsi murni memiliki dua kualitas:

  1. Menyebutnya berulang kali dengan input yang sama selalu memberikan hasil yang sama. Ini menyiratkan bahwa itu tidak berubah. Keadaannya diatur hanya sekali.

  2. Tidak menghasilkan efek samping. Satu-satunya perubahan yang disebabkan oleh panggilan itu adalah menghasilkan hasilnya

Jadi, bagaimana seseorang berfungsi murni jika Anda telah bersumpah menggunakan returncara Anda mengkomunikasikan hasil?

The kirim, jangan tanya karya ide dengan menggunakan apa yang beberapa akan mempertimbangkan efek samping. Ketika saya berurusan dengan suatu objek saya tidak menanyakannya tentang keadaan internalnya. Saya katakan apa yang harus saya lakukan dan menggunakan keadaan internal untuk mencari tahu apa yang harus dilakukan dengan apa yang saya perintahkan. Setelah saya katakan, saya tidak bertanya apa yang dilakukannya. Saya hanya berharap itu telah melakukan sesuatu tentang apa yang diperintahkan untuk dilakukan.

Saya memikirkan Tell, Don't Ask sebagai lebih dari sekedar nama yang berbeda untuk enkapsulasi. Ketika saya menggunakan returnsaya tidak tahu apa yang memanggil saya. Saya tidak dapat berbicara protokol itu, saya harus memaksanya untuk berurusan dengan protokol saya. Yang dalam banyak kasus dinyatakan sebagai keadaan internal. Bahkan jika apa yang diekspos tidak benar-benar keadaan itu biasanya hanya beberapa perhitungan dilakukan pada keadaan dan masukan argumen. Memiliki antarmuka untuk merespons melalui pemberian kesempatan untuk memijat hasil menjadi sesuatu yang lebih bermakna daripada keadaan internal atau perhitungan. Itu adalah pesan yang lewat . Lihat contoh ini .

Kembali ke masa lalu, ketika disk drive benar-benar memiliki disk di dalamnya dan thumb drive adalah apa yang Anda lakukan di dalam mobil ketika roda terlalu dingin untuk disentuh dengan jari-jari Anda, saya diajari bagaimana orang yang menjengkelkan mempertimbangkan fungsi yang memiliki parameter. void swap(int *first, int *second)tampak sangat berguna tetapi kami didorong untuk menulis fungsi yang mengembalikan hasilnya. Jadi saya menaruh hati ini pada iman dan mulai mengikutinya.

Tapi sekarang saya melihat orang-orang membangun arsitektur di mana objek membiarkan bagaimana mereka dibangun mengendalikan ke mana mereka mengirim hasilnya. Inilah contoh implementasi . Menyuntikkan objek port keluaran sepertinya sedikit seperti ide parameter keluar lagi. Tapi begitulah cara mengatakan-jangan-tanya benda memberi tahu objek lain apa yang telah mereka lakukan.

Ketika saya pertama kali belajar tentang efek samping saya menganggapnya seperti parameter output. Kami diberitahu untuk tidak mengejutkan orang-orang dengan membuat beberapa pekerjaan terjadi dengan cara yang mengejutkan, yaitu dengan tidak mengikuti return resultkonvensi. Sekarang tentu, saya tahu ada tumpukan masalah threading asynchronous paralel yang efek samping bercampur dengan tetapi kembali benar-benar hanya sebuah konvensi yang membiarkan Anda mendorong hasilnya pada tumpukan sehingga apa pun yang disebut Anda dapat mematikannya nanti. Hanya itu yang sebenarnya.

Apa yang sebenarnya ingin saya tanyakan:

Apakah returnsatu-satunya cara untuk menghindari semua efek samping kesengsaraan dan mendapatkan keselamatan benang tanpa kunci, dll. Atau bisakah saya mengikuti ceritanya, jangan bertanya dengan cara yang murni fungsional?

candied_orange
sumber
3
Jika Anda memilih untuk tidak mengabaikan Pemisahan Permintaan Perintah, apakah Anda menganggap masalah Anda terpecahkan?
rwong
30
Pertimbangkan bahwa menemukan diri Anda pada tendangan mungkin merupakan indikasi bahwa Anda terlibat dalam desain dogma-driven daripada menimbang-nimbang pro dan kontra dari setiap situasi tertentu.
Blrfl
3
Secara umum ketika orang berbicara tentang "kembali" menjadi berbahaya mereka mengatakan itu menentang pemrograman terstruktur, tidak fungsional, dan pernyataan pengembalian tunggal pada akhir rutin (dan mungkin pada akhir kedua sisi blok if / else yang sendiri elemen terakhir) tidak termasuk dalam hal itu.
Random832
16
@jameslarge: Dikotomi Salah. Tidak membiarkan diri Anda didorong ke desain oleh pemikiran dogmatis bukanlah hal yang sama dengan Wild West / semuanya berjalan mendekati yang Anda bicarakan. Intinya adalah untuk tidak membiarkan dogma menghalangi kode yang baik, sederhana, dan jelas. Hukum universal adalah untuk kekurangan; konteksnya adalah untuk raja.
Nicol Bolas
4
Ada satu hal bagi saya yang tidak jelas dalam pertanyaan Anda: Anda mengatakan Anda telah bersumpah menggunakan 'kembali', tetapi sejauh yang saya bisa katakan Anda tidak secara eksplisit menghubungkannya dengan konsep Anda yang lain atau mengatakan mengapa Anda melakukan ini. Ketika dikombinasikan dengan definisi fungsi murni termasuk menghasilkan hasil, Anda membuat sesuatu yang tidak mungkin diselesaikan.
Danikov

Jawaban:

96

Jika suatu fungsi tidak memiliki efek samping dan tidak mengembalikan apa pun, maka fungsi tersebut tidak berguna. Sesederhana itu.

Tapi saya kira Anda bisa menggunakan beberapa cheat jika Anda ingin mengikuti surat aturan dan mengabaikan alasan yang mendasarinya. Misalnya menggunakan parameter keluar secara tegas tidak menggunakan return. Tetapi masih tetap sama persis dengan pengembalian, hanya dengan cara yang lebih berbelit-belit. Jadi, jika Anda yakin pengembalian buruk karena suatu alasan , maka menggunakan parameter keluar jelas buruk karena alasan mendasar yang sama.

Anda dapat menggunakan lebih banyak cheat yang berbelit-belit. Misalnya Haskell terkenal dengan trik IO monad di mana Anda dapat memiliki efek samping dalam praktek, tetapi masih belum sepenuhnya memiliki efek samping dari sudut pandang teoritis. Gaya kelanjutan-lewat adalah trik lain, yang memungkinkan Anda menghindari pengembalian dengan mengubah kode Anda menjadi spageti.

Intinya adalah, tidak ada trik konyol, dua prinsip fungsi bebas efek samping dan "tidak ada pengembalian" sama sekali tidak kompatibel. Lebih lanjut saya akan menunjukkan keduanya adalah prinsip yang benar-benar buruk (dogma benar-benar) pada awalnya, tetapi itu adalah diskusi yang berbeda.

Aturan seperti "katakan, jangan tanya" atau "tidak ada efek samping" tidak dapat diterapkan secara universal. Anda selalu harus mempertimbangkan konteksnya. Program tanpa efek samping benar-benar tidak berguna. Bahkan bahasa fungsional murni pun mengakui hal itu. Sebaliknya mereka berusaha untuk memisahkan bagian murni dari kode dari yang dengan efek samping. Titik State atau IO monads di Haskell bukanlah bahwa Anda menghindari efek samping - karena Anda tidak bisa - tetapi keberadaan efek samping secara eksplisit ditunjukkan oleh tanda tangan fungsi.

Aturan tell-dont-ask berlaku untuk jenis arsitektur yang berbeda - gaya di mana objek dalam program adalah "aktor" independen yang berkomunikasi satu sama lain. Setiap aktor pada dasarnya otonom dan terbungkus. Anda dapat mengirimnya pesan dan memutuskan bagaimana bereaksi terhadapnya, tetapi Anda tidak dapat memeriksa keadaan internal aktor dari luar. Ini berarti Anda tidak dapat memberi tahu apakah sebuah pesan mengubah keadaan internal aktor / objek. Keadaan dan efek samping disembunyikan oleh desain .

JacquesB
sumber
20
@CandiedOrange: Apakah suatu metode memiliki efek samping secara langsung atau tidak langsung meskipun banyak lapisan panggilan tidak mengubah apa pun secara konseptual. Itu masih efek samping. Tetapi jika intinya adalah bahwa efek samping hanya terjadi melalui benda yang disuntikkan sehingga Anda mengendalikan jenis efek samping apa yang mungkin terjadi, maka ini terdengar seperti desain yang bagus. Ini tidak bebas efek samping. Ini adalah OO yang baik tetapi tidak sepenuhnya berfungsi.
JacquesB
12
@LightnessRacesinOrbit: grep dalam mode sunyi memiliki kode pengembalian proses yang akan digunakan. Jika tidak memilikinya, maka itu benar-benar akan sia
unperson325680
10
@progo: Kode pengembalian bukan efek samping; itu yang berlaku. Apa pun yang kita sebut efek samping disebut efek samping karena itu bukan kode pengembalian;)
Lightness Races with Monica
8
@Cubic itulah intinya. Program tanpa efek samping tidak berguna.
Jens Schauder
5
@ mathreadler Itu efek samping :)
Andres F.
32

Katakan, Don't Ask disertai dengan beberapa asumsi mendasar:

  1. Anda menggunakan benda.
  2. Objek Anda memiliki status.
  3. Keadaan objek Anda memengaruhi perilaku mereka.

Tidak satu pun dari hal-hal ini berlaku untuk fungsi murni.

Jadi mari kita tinjau mengapa kita memiliki aturan "Katakan, Jangan Tanyakan." Aturan ini adalah peringatan dan pengingat. Dapat diringkas seperti ini:

Izinkan kelas Anda untuk mengelola negaranya sendiri. Jangan meminta statusnya, dan kemudian mengambil tindakan berdasarkan kondisi itu. Beri tahu kelas apa yang Anda inginkan, dan biarkan ia memutuskan apa yang harus dilakukan berdasarkan negaranya sendiri.

Dengan kata lain, kelas semata-mata bertanggung jawab untuk mempertahankan negara mereka sendiri dan menindaklanjutinya. Ini adalah tentang enkapsulasi.

Dari Fowler :

Tell-Don't-Ask adalah prinsip yang membantu orang mengingat bahwa orientasi objek adalah tentang menggabungkan data dengan fungsi yang beroperasi pada data tersebut. Ini mengingatkan kita bahwa alih-alih meminta objek untuk data dan bertindak atas data itu, kita malah harus memberi tahu objek apa yang harus dilakukan. Ini mendorong kita untuk memindahkan perilaku ke objek untuk pergi dengan data.

Untuk menegaskan kembali, semua ini tidak ada hubungannya dengan fungsi murni, atau bahkan yang tidak murni kecuali Anda mengekspos keadaan kelas ke dunia luar. Contoh:

Pelanggaran TDA

var color = trafficLight.Color;
var elapsed = trafficLight.Elapsed;
If (color == Color.Red && elapsed > 2.Minutes)
    trafficLight.ChangeColor(green);

Bukan Pelanggaran TDA

var result = trafficLight.ChangeColor(Color.Green);

atau

var result = await trafficLight.ChangeColorWhenReady(Color.Green);     

Dalam kedua contoh terakhir, lampu lalu lintas mempertahankan kontrol negara dan tindakannya.

Robert Harvey
sumber
Tunggu sebentar, penutupan bisa murni. mereka memiliki negara (mereka menyebutnya ruang lingkup leksikal). dan bahwa ruang lingkup leksikal dapat mempengaruhi perilaku mereka. Apakah Anda yakin TDA hanya relevan ketika objek terlibat?
candied_orange
7
Penutupan @CandiedOrange hanya murni jika Anda tidak memodifikasi binding yang tertutup. Kalau tidak, Anda kehilangan transparansi referensial saat memanggil fungsi yang dikembalikan dari penutupan.
Jared Smith
1
@ JaredSmith dan tidakkah hal yang sama berlaku ketika Anda berbicara tentang objek Bukankah ini hanya masalah ketidakberdayaan?
candied_orange
1
@ bdsl - Dan sekarang Anda secara tidak sengaja menunjukkan dengan tepat di mana setiap diskusi dengan tipe ini sesuai dengan trafficLight.refreshDisplay Anda. Jika Anda mengikuti aturan, Anda mengarah ke sistem yang sangat fleksibel yang tidak dipahami oleh siapa pun selain pembuat kode asli. Saya bahkan berani bertaruh bahwa setelah beberapa tahun hiatus bahkan pembuat kode asli mungkin tidak akan mengerti apa yang mereka lakukan.
Dunk
1
"Konyol", seperti dalam "Jangan buka benda lain dan jangan melihat isi perutnya tetapi sebaliknya tumpahkan nyali Anda sendiri (jika Anda punya) ke dalam metode objek lain; itulah Jalan" - konyol.
Joker_vD
30

Ketika saya berurusan dengan suatu objek saya tidak menanyakannya tentang keadaan internalnya. Saya katakan apa yang harus saya lakukan dan menggunakan keadaan internal untuk mencari tahu apa yang harus dilakukan dengan apa yang saya katakan untuk dilakukan.

Anda tidak hanya meminta status internal , Anda juga tidak bertanya apakah itu memiliki kondisi internal sama sekali .

Katakan juga , jangan tanya! tidak tidak berarti tidak mendapatkan hasil dalam bentuk nilai kembali (disediakan oleh returnpernyataan dalam metode). Itu hanya menyiratkan saya tidak peduli bagaimana Anda melakukannya, tetapi lakukan pemrosesan itu! . Dan terkadang Anda langsung menginginkan hasil prosesnya ...

Timothy Truckle
sumber
1
CQS meskipun akan menyiratkan bahwa memodifikasi negara dan mendapatkan hasil harus dipisahkan
jk.
7
@jk. Seperti biasa: secara umum Anda harus memisahkan perubahan negara dan mengembalikan hasil tetapi dalam kasus yang jarang ada alasan yang sah untuk menggabungkan itu. Contoh: next()metode iterators seharusnya tidak hanya mengembalikan objek saat ini tetapi juga mengubah keadaan internal iterator sehingga panggilan berikutnya mengembalikan objek berikutnya ...
Timothy Truckle
4
Persis. Saya pikir masalah OP hanya karena kesalahpahaman / kesalahpahaman "katakan, jangan tanya". Dan memperbaiki kesalahpahaman itu membuat masalah hilang.
Konrad Rudolph
@KonradRudolph Plus, saya kira itu bukan satu-satunya kesalahpahaman di sini. Deskripsi mereka tentang "fungsi murni" termasuk "Keadaannya diatur hanya sekali." Komentar lain menunjukkan itu bisa berarti konteks penutupan, tetapi frasa itu terdengar aneh bagi saya.
Izkata
17

Jika Anda dianggap returnsebagai "berbahaya" (untuk tetap di gambar Anda), maka alih-alih membuat fungsi seperti

ResultType f(InputType inputValue)
{
     // ...
     return result;
}

membangunnya dengan cara menyampaikan pesan:

void f(InputType inputValue, Action<ResultType> g)
{
     // ...
     g(result);
}

Selama fdan gbebas efek samping, merantai mereka bersama-sama akan bebas efek samping juga. Saya pikir gaya ini mirip dengan apa yang juga disebut gaya Continuation-passing .

Jika ini benar-benar mengarah ke program "lebih baik" masih bisa diperdebatkan, karena itu melanggar beberapa konvensi. Insinyur perangkat lunak Jerman Ralf Westphal membuat seluruh model pemrograman di sekitar ini, ia menyebutnya "Event Based Components" dengan teknik pemodelan yang ia sebut "Flow Design".

Untuk melihat beberapa contoh, mulai di bagian "Menerjemahkan ke Acara" pada entri blog ini . Untuk pendekatan penuh, saya merekomendasikan e-book-nya "Pesan sebagai model Pemrograman - Melakukan OOP seolah-olah Anda bersungguh-sungguh" .

Doc Brown
sumber
24
If this really leads to "better" programs is debatableKita hanya perlu melihat kode yang ditulis dalam JavaScript selama dekade pertama abad ini. Jquery dan pluginsnya rentan terhadap paradigma callback ini ... callback di mana-mana . Pada titik tertentu, terlalu banyak panggilan balik bersarang , menjadikan debugging sebagai mimpi buruk. Kode masih harus dibaca oleh manusia terlepas dari keeksentrikan dari rekayasa perangkat lunak dan "prinsip-prinsipnya"
Laiv
1
bahkan di beberapa titik Anda perlu memberikan tindakan yang melakukan efek samping atau Anda perlu beberapa cara untuk kembali dari bagian CPS
jk.
12
@Laiv CPS diciptakan sebagai teknologi optimisasi untuk kompiler, tidak ada yang benar-benar mengharapkan programmer untuk menulis kode dengan cara ini.
Joker_vD
3
@CandiedOrange Dalam bentuk slogan, "return hanya memberitahu kelanjutan apa yang harus dilakukan". Memang, penciptaan Skema termotivasi dengan mencoba memahami model Aktor Hewitt dan sampai pada kesimpulan bahwa aktor dan penutupan adalah hal yang sama.
Derek Elkins
2
Secara hipotesis, tentu saja, Anda dapat menulis seluruh aplikasi Anda sebagai serangkaian panggilan fungsi yang tidak mengembalikan apa pun. Jika Anda tidak keberatan itu dipasangkan dengan erat, Anda bahkan tidak membutuhkan porta. Tetapi sebagian besar aplikasi waras menggunakan fungsi yang mengembalikan sesuatu, karena ... well, mereka waras. Dan karena saya yakin saya sudah cukup menunjukkan dalam jawaban saya, Anda dapat returndata dari fungsi dan masih mematuhi Tell Don't Ask, selama Anda tidak mengambil alih status objek.
Robert Harvey
7

Pesan yang lewat secara inheren efektif. Jika Anda memberi tahu objek untuk melakukan sesuatu, Anda berharap itu memiliki efek pada sesuatu. Jika penangan pesan murni, Anda tidak perlu mengirimnya pesan.

Dalam sistem aktor terdistribusi, hasil operasi biasanya dikirim sebagai pesan kembali ke pengirim permintaan asli. Pengirim pesan secara implisit disediakan oleh runtime aktor, atau (secara konvensional) diteruskan secara eksplisit sebagai bagian dari pesan tersebut. Dalam pengiriman pesan yang sinkron, satu respons mirip dengan returnpernyataan. Dalam pengiriman pesan yang tidak sinkron, menggunakan pesan respons sangat berguna karena memungkinkan untuk pemrosesan bersamaan di banyak aktor sambil tetap memberikan hasil.

Melewati "pengirim" yang hasilnya harus dikirim secara eksplisit pada dasarnya memodelkan gaya kelanjutan meneruskan atau parameter yang ditakuti - kecuali bahwa ia mengirimkan pesan kepada mereka alih-alih memutasikan mereka secara langsung.

Bergi
sumber
5

Seluruh pertanyaan ini menurut saya sebagai 'pelanggaran tingkat'.

Anda memiliki (setidaknya) level berikut dalam proyek besar:

  • Level sistem, misalnya platform e-commerce
  • Level sub-sistem mis validasi pengguna: server, AD, front-end
  • Tingkat program individu, misalnya salah satu komponen di atas
  • Tingkat Aktor / Modul [ini menjadi suram tergantung pada bahasa]
  • Tingkat metode / fungsi.

Dan seterusnya ke token individu.

Sebenarnya tidak ada kebutuhan untuk entitas pada tingkat metode / fungsi untuk tidak kembali (bahkan jika itu hanya kembali this). Dan tidak ada (dalam deskripsi Anda) kebutuhan untuk entitas di tingkat Aktor untuk mengembalikan apa pun (tergantung pada bahasa yang bahkan tidak mungkin). Saya pikir kebingungan dalam menyatukan kedua level tersebut, dan saya berpendapat bahwa mereka harus beralasan dengan jelas (bahkan jika objek yang diberikan benar-benar menjangkau beberapa level).

Jared Smith
sumber
2

Anda menyebutkan bahwa Anda ingin menyesuaikan diri dengan prinsip OOP "katakan, jangan tanya" dan prinsip fungsional dari fungsi murni, tetapi saya tidak begitu mengerti bagaimana hal itu membuat Anda menghindari pernyataan pengembalian.

Cara alternatif yang relatif umum untuk mengikuti kedua prinsip ini adalah dengan mengikuti semua pernyataan pengembalian dan menggunakan objek tidak permanen dengan pengambil saja. Maka pendekatannya adalah agar beberapa getter mengembalikan objek yang mirip dengan status baru, sebagai lawan mengubah keadaan objek asli.

Salah satu contoh dari pendekatan ini adalah dalam tipe data Python builtin tupledan frozenset. Berikut ini adalah penggunaan khas frozenset:

small_digits = frozenset([0, 1, 2, 3, 4])
big_digits = frozenset([5, 6, 7, 8, 9])
all_digits = small_digits.union(big_digits)

print("small:", small_digits)
print("big:", big_digits)
print("all:", all_digits)

Yang akan mencetak berikut ini, menunjukkan bahwa metode penyatuan menciptakan frozenset baru dengan statusnya sendiri tanpa mempengaruhi objek lama:

kecil: frozenset ({0, 1, 2, 3, 4})

besar: frozenset ({5, 6, 7, 8, 9})

semua: frozenset ({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})

Contoh ekstensif lain dari struktur data tidak berubah yang serupa adalah perpustakaan Immutable.js Facebook . Dalam kedua kasus Anda mulai dengan blok bangunan ini dan dapat membangun objek domain tingkat tinggi yang mengikuti prinsip yang sama, mencapai pendekatan OOP fungsional, yang membantu Anda merangkum data dan alasan tentang hal itu dengan lebih mudah. Dan kekekalan juga memungkinkan Anda menuai manfaat karena dapat berbagi objek tersebut di antara utas tanpa harus khawatir tentang kunci.

yoniLavi
sumber
1

Saya curiga bahwa kode yang ditulis dengan baik dapat mengikuti prinsip-prinsip OO dan prinsip-prinsip fungsional secara bersamaan. Saya mencoba untuk mendamaikan ide-ide ini dan poin penting yang saya dapatkan adalah kembali.

Saya sudah mencoba yang terbaik untuk mendamaikan beberapa manfaat, lebih khusus, pemrograman imperatif dan fungsional (secara alami tidak mendapatkan semua manfaat apa pun, tetapi mencoba untuk mendapatkan bagian terbesar dari keduanya), meskipun returnsebenarnya penting untuk melakukan itu di mode sederhana bagi saya dalam banyak kasus.

Sehubungan dengan mencoba menghindari returnpernyataan langsung, saya mencoba untuk merenungkan hal ini selama satu jam terakhir dan pada dasarnya menumpuk meluap otak saya beberapa kali. Saya dapat melihat daya tariknya dalam hal menegakkan tingkat enkapsulasi dan informasi terkuat yang mendukung objek-objek yang sangat otonom yang hanya diberi tahu apa yang harus dilakukan, dan saya suka menjelajahi ekstremitas gagasan jika hanya mencoba untuk menjadi lebih baik memahami bagaimana mereka bekerja.

Jika kita menggunakan contoh lampu lalu lintas, maka segera upaya naif akan ingin memberikan pengetahuan lampu lalu lintas seperti itu dari seluruh dunia yang mengelilinginya, dan itu tentu saja tidak diinginkan dari perspektif penggandengan. Jadi, jika saya mengerti dengan benar, Anda abstrak itu dan berpisah demi generalisasi konsep port I / O yang selanjutnya menyebarkan pesan dan permintaan, bukan data, melalui pipa, dan pada dasarnya menyuntikkan objek-objek ini dengan interaksi / permintaan yang diinginkan antara satu sama lain sementara tidak menyadari satu sama lain.

Pipa Nodal

masukkan deskripsi gambar di sini

Dan diagram itu adalah tentang sejauh saya mencoba untuk membuat sketsa ini (dan walaupun sederhana, saya harus terus mengubahnya dan memikirkannya kembali). Segera saya cenderung berpikir desain dengan tingkat decoupling dan abstraksi ini akan menemukan jalannya menjadi sangat sulit untuk dipertimbangkan dalam bentuk kode, karena orkestra yang menghubungkan semua hal ini ke dunia yang kompleks mungkin merasa sangat sulit untuk melacak semua interaksi dan permintaan ini untuk membuat saluran pipa yang diinginkan. Namun, dalam bentuk visual, mungkin cukup mudah untuk hanya menggambar hal-hal ini sebagai grafik dan menghubungkan semuanya dan melihat hal-hal terjadi secara interaktif.

Dalam hal efek samping, saya bisa melihat ini bebas dari "efek samping" dalam arti bahwa permintaan ini dapat, pada tumpukan panggilan, mengarah ke rantai perintah untuk setiap utas untuk melakukan, misalnya (saya tidak menghitung ini sebagai "efek samping" dalam arti pragmatis karena tidak mengubah keadaan yang relevan dengan dunia luar sampai perintah tersebut benar-benar dieksekusi - tujuan praktis bagi saya dalam sebagian besar perangkat lunak bukan untuk menghilangkan efek samping tetapi menunda dan memusatkannya) . Dan lebih jauh lagi, eksekusi perintah dapat menghasilkan dunia baru yang bertentangan dengan mutasi yang sudah ada. Otak saya benar-benar dikenakan pajak hanya mencoba memahami semua ini namun, tidak ada upaya prototipe ide-ide ini. Saya juga tidak

Bagaimana itu bekerja

Jadi untuk memperjelas saya membayangkan bagaimana Anda sebenarnya memprogram ini. Cara saya melihatnya bekerja sebenarnya adalah diagram di atas yang menangkap alur kerja user-end (programmer). Anda dapat menyeret lampu lalu lintas ke dunia, menyeret pengatur waktu, memberinya periode yang telah berlalu (saat "membuat" itu). Timer memiliki On Intervalacara (port keluaran), Anda dapat menghubungkannya ke lampu lalu lintas sehingga pada acara semacam itu, ia memberi tahu lampu untuk menelusuri warna-warnanya.

Lalu lintas lampu mungkin, pada beralih ke warna tertentu, memancarkan output (peristiwa) seperti,, On Redpada titik mana kita mungkin menyeret pejalan kaki ke dunia kita dan membuat acara itu memberitahu pejalan kaki untuk mulai berjalan ... atau kita mungkin menyeret burung ke pemandangan kami dan membuatnya jadi ketika cahaya berubah menjadi merah, kami memberitahu burung untuk mulai terbang dan mengepakkan sayap mereka ... atau mungkin ketika cahaya berubah menjadi merah, kami memberi tahu sebuah bom untuk meledak - apa pun yang kita inginkan, dan dengan benda-benda menjadi sepenuhnya tidak menyadari satu sama lain, dan tidak melakukan apa pun kecuali secara tidak langsung saling memberi tahu apa yang harus dilakukan melalui konsep input / output abstrak ini.

Dan mereka sepenuhnya merangkum keadaan mereka dan tidak mengungkapkan apa-apa tentang hal itu (kecuali jika "peristiwa" ini dianggap sebagai TMI, pada titik mana saya harus memikirkan kembali banyak hal), mereka mengatakan satu sama lain untuk melakukan secara tidak langsung, mereka tidak bertanya. Dan mereka terpisah. Tidak ada yang tahu tentang apa pun kecuali abstraksi port input / output umum ini.

Kasus Penggunaan Praktis?

Saya bisa melihat jenis hal ini berguna sebagai bahasa tertanam tingkat-domain-spesifik tingkat tinggi dalam domain tertentu untuk mengatur semua objek otonom ini yang tidak tahu apa-apa tentang dunia sekitarnya, tidak mengekspos apa pun dari konstruksi pos negara internal mereka, dan pada dasarnya hanya menyebarkan permintaan antara satu sama lain yang bisa kita ubah dan sesuaikan dengan isi hati kita. Saat ini saya merasa ini sangat spesifik untuk domain, atau mungkin saya belum cukup memikirkannya, karena sangat sulit bagi saya untuk membungkus otak saya dengan hal-hal yang saya kembangkan secara teratur (saya sering bekerja dengan kode tingkat menengah ke bawah) jika saya menafsirkan Tell, Don't Ask untuk ekstremitas seperti itu dan menginginkan tingkat enkapsulasi terkuat yang bisa dibayangkan. Tetapi jika kita bekerja dengan abstraksi tingkat tinggi dalam domain tertentu,

Sinyal dan Slot

Desain ini tampak aneh bagi saya sampai saya menyadari itu pada dasarnya sinyal dan slot jika kita tidak mengambil banyak nuansa bagaimana itu diterapkan ke dalam akun. Pertanyaan utama bagi saya adalah seberapa efektif kita dapat memprogram masing-masing node (objek) ini dalam grafik yang secara ketat mengikuti Tell, Don't Ask, sampai pada tingkat menghindari returnpernyataan, dan apakah kita dapat mengevaluasi grafik tersebut tanpa mutasi (dalam paralel, misalnya, tidak ada penguncian). Di situlah manfaat magisnya bukanlah dalam cara kita menghubungkan hal-hal ini bersama-sama secara potensial, tetapi bagaimana mereka dapat diimplementasikan ke tingkat enkapsulasi ini tanpa adanya mutasi. Kedua hal ini tampaknya layak untuk saya, tetapi saya tidak yakin seberapa luas itu akan berlaku, dan di situlah saya agak bingung mencoba untuk bekerja melalui kasus penggunaan potensial.

Energi Naga
sumber
0

Saya jelas melihat kebocoran kepastian di sini. Tampaknya "efek samping" adalah istilah yang dikenal dan dipahami secara umum, tetapi kenyataannya tidak. Bergantung pada definisi Anda (yang sebenarnya hilang dalam OP), efek samping mungkin benar-benar diperlukan (seperti yang dijelaskan oleh @JacquesB), atau tanpa ampun diterima. Atau, membuat satu langkah menuju klarifikasi, ada kebutuhan untuk membedakan antara efek samping yang diinginkan yang tidak ingin disembunyikan (pada titik ini IO Haskell yang terkenal muncul: itu hanyalah cara untuk menjadi eksplisit) dan efek samping yang tidak diinginkan sebagai hasil dari bug kode dan hal-hal semacam itu . Itu adalah masalah yang sangat berbeda dan karenanya memerlukan alasan yang berbeda.

Jadi, saya sarankan untuk memulai dari pengubahan ulang kata-kata Anda sendiri: "Bagaimana kita mendefinisikan efek samping dan apa yang diberikan definisi tentang keterkaitannya dengan pernyataan" kembali "?".

Sereja Bogolubov
sumber
1
"pada titik ini IO Haskell yang terkenal muncul: itu tidak lain adalah cara untuk menjadi eksplisit" - kesaksian jelas merupakan keuntungan dari IO monadik Haskell, tetapi ada poin lain untuk itu: ia menyediakan cara untuk mengisolasi efek samping menjadi sepenuhnya di luar bahasa - meskipun implementasi umum tidak benar - benar melakukan hal ini, sebagian besar karena masalah efisiensi, secara konseptual itu benar: IO monad dapat dianggap sebagai cara mengembalikan instruksi ke beberapa lingkungan yang sepenuhnya di luar lingkungan. Program Haskell, bersama dengan referensi ke fungsi untuk melanjutkan setelah selesai.
Jules