Apa masalah membawa const C ++ - like ke dalam bahasa?

17

Saya tertarik pada ide C ++ - seperti consttidak eksekusi tertentu (seperti membuang const).

Ambil contoh C # - tidak memiliki C ++ - seperti const, dan alasannya adalah biasa - orang dan waktu. Di sini juga tampaknya tim C # melihat eksekusi C ++ dari const, pemasaran CLR dan sudah cukup pada saat ini (lihat mengapa tidak ada metode anggota const dalam parameter c # dan const ; terima kasih Svick). Jadilah jika kita bergerak lebih jauh dari itu, apakah ada yang lain?

Apakah ada sesuatu yang lebih dalam? Ambil contoh multi-inheritance - biasanya dianggap sulit untuk dipahami (untuk pengguna) dan dengan demikian tidak ditambahkan ke bahasa (seperti masalah intan).

Apakah ada sesuatu di NATURE dari constyang berpose masalah bahwa lebih baik untuk bahasa untuk menghindarinya? Sesuatu seperti memutuskan apakah constharus dalam atau dangkal (memiliki constwadah artinya saya tidak dapat menambahkan elemen baru atau mengubah elemen yang ada juga; bagaimana jika elemen-elemen tersebut dari tipe referensi)?

UPDATE : sementara saya menyebutkan C #, dan dengan demikian membuat perspektif sejarah saya tertarik pada sifat masalah potensial constke bahasa.

Ini bukan tantangan bahasa. Harap abaikan faktor-faktor seperti tren atau popularitas saat ini - Saya hanya tertarik pada masalah teknis - terima kasih.

Greenoldman
sumber
3
sebagai tambahan: multiple inheritance mungkin tidak sulit untuk dipahami, tetapi resolusi metode bisa menjadi sangat jelek. Resolusi depth-first yang naif dengan cepat menjadi tidak intuitif (" masalah intan "). Urutan resolusi metode C3 (diterbitkan '96) memecahkan ini, tetapi tentu saja tidak mudah dimengerti. Oleh karena itu, pelarangan pewarisan berganda seringkali tampak cukup masuk akal - tetapi masalah sebenarnya adalah bahwa Java mendahului algoritma C3, dan C # berorientasi sendiri setelah Java.
amon
3
@amon Banyak orang tidak benar-benar berpikir multiple inheritence adalah fitur yang ingin Anda miliki, misalnya, pencipta languge pemrograman D: Ini adalah fitur kompleks dari nilai yang dapat diperdebatkan. Sangat sulit untuk diimplementasikan secara efisien, dan kompiler rentan terhadap banyak bug dalam mengimplementasikannya. Hampir semua nilai MI dapat ditangani dengan pewarisan tunggal ditambah dengan antarmuka dan agregasi. Apa yang tersisa tidak membenarkan bobot implementasi MI. (sumber)
jcora
2
Bahkan tanpa Multiple Inheritance, Anda sudah dapat menyandikan masalah 3-SAT sebagai Resolusi Metode (atau lebih tepatnya Resolusi Kelebihan) di C #, sehingga menjadikannya NP-complete.
Jörg W Mittag
1
@vick, terima kasih banyak. Karena saya tidak punya jawaban untuk pertanyaan ini, saya mengambil kebebasan mengeditnya, untuk fokus pada sifat masalah, bukan alasan historis, karena sepertinya 99% dari mereka adalah "waktu + orang + anti C ++ bias + CLR ".
greenoldman

Jawaban:

10

Catatan yakin jika ini memenuhi syarat untuk Anda, tetapi dalam bahasa fungsional seperti Standar ML semuanya tidak dapat diubah secara default. Mutasi didukung melalui tipe generik reference. Jadi intvariabel tidak berubah, dan ref intvariabel adalah wadah yang bisa berubah untuk ints. Pada dasarnya, variabel adalah variabel nyata dalam arti matematika (nilai yang tidak diketahui tetapi tetap) dan refs adalah "variabel" dalam arti pemrograman imperatif - sel memori yang dapat ditulis dan dibaca. (Saya suka menyebutnya mereka tugas .)

Saya pikir masalahnya constadalah dua kali lipat. Pertama, C ++ tidak memiliki pengumpulan sampah, yang diperlukan untuk memiliki struktur data persisten non-sepele . const harus mendalam untuk masuk akal, namun memiliki nilai yang sepenuhnya tidak dapat diubah dalam C ++ tidak praktis.

Kedua, di C ++ Anda harus memilih untuk ikut serta constdaripada menyisih. Tetapi ketika Anda lupa constsesuatu dan kemudian memperbaikinya, Anda akan berakhir dalam situasi "keracunan const" yang disebutkan dalam jawaban @ RobY di mana constperubahan akan mengalir di seluruh kode. Jika constitu default, Anda tidak akan menemukan diri Anda berlaku constsurut. Selain itu, harus menambahkan di constmana-mana menambahkan banyak suara ke kode.

Saya menduga bahasa umum yang mengikuti (misalnya Jawa) sangat dibentuk oleh keberhasilan dan cara berpikir C dan C ++. Contoh kasus, bahkan dengan pengumpulan sampah, sebagian besar API pengumpulan bahasa mengasumsikan struktur data yang bisa berubah. Fakta bahwa semuanya bisa berubah dan ketidakmampuan dilihat sebagai kasus sudut berbicara banyak tentang pola pikir imperatif di balik bahasa populer.

EDIT : Setelah merenungkan komentar greenoldman, saya menyadari bahwa constitu tidak secara langsung tentang kekekalan data; constmengkodekan ke dalam jenis metode apakah itu memiliki efek samping pada instance.

Dimungkinkan untuk menggunakan mutasi untuk mencapai perilaku yang transparan secara referensial . Misalkan Anda memiliki fungsi yang ketika dipanggil berturut-turut mengembalikan nilai yang berbeda - misalnya, fungsi yang membaca satu karakter dari stdin. Kita dapat menggunakan cache / memoize hasil dari fungsi ini untuk menghasilkan aliran nilai yang secara referensi transparan. Aliran akan menjadi daftar yang ditautkan yang simpulnya akan memanggil fungsi saat pertama kali Anda mencoba mengambil nilainya, tetapi kemudian menyimpan hasilnya. Jadi jika stdinterkoneksi Hello, world!, pertama kali Anda mencoba mengambil nilai dari simpul pertama, itu akan membaca satu chardan kembali H. Setelah itu akan terus kembali Htanpa panggilan lebih lanjut untuk membaca a char. Demikian juga, simpul kedua akan membaca chardaristdinpertama kali Anda mencoba mengambil nilainya, kali ini kembali edan menyimpan hasilnya.

Hal yang menarik di sini adalah bahwa Anda telah mengubah proses yang secara inheren stateful menjadi objek yang tampaknya tanpa kewarganegaraan. Namun, perlu untuk memutasikan keadaan internal objek (dengan menyimpan hasil) untuk mencapai ini - mutasi adalah efek jinak . Tidak mungkin membuat kami CharStream constmeskipun aliran berperilaku seperti nilai yang tidak berubah. Sekarang bayangkan ada Streamantarmuka dengan constmetode, dan semua fungsi Anda harapkan const Streams. Anda CharStreamtidak dapat mengimplementasikan antarmuka!

( EDIT 2: Rupanya ada kata kunci C ++ yang disebut mutableyang akan memungkinkan kita untuk berbuat curang dan membuatCharStream const . Namun, celah ini menghancurkan constjaminan - sekarang Anda benar-benar tidak dapat memastikan sesuatu tidak akan bermutasi melalui constmetodenya. Saya kira itu bukan itu buruk karena Anda harus secara eksplisit meminta celah, tetapi Anda masih sepenuhnya bergantung pada sistem kehormatan.)

Kedua, anggaplah Anda memiliki fungsi tingkat tinggi - yaitu, Anda bisa meneruskan fungsi sebagai argumen ke fungsi lain. constness adalah bagian dari tanda tangan suatu fungsi, jadi Anda tidak akan bisa meneruskan nonfungsi constsebagai argumen ke fungsi yang mengharapkan constfungsi. Menegakkan secara buta di constsini akan menyebabkan hilangnya keumuman.

Akhirnya, memanipulasi constobjek tidak menjamin bahwa itu tidak bermutasi beberapa keadaan eksternal (statis atau global) di belakang Anda, jadi constjaminan tidak sekuat yang awalnya muncul.

Tidak jelas bagi saya bahwa pengkodean ada atau tidaknya efek samping ke dalam sistem tipe secara universal adalah hal yang baik.

Doval
sumber
1
+1 terima kasih. Objek yang tidak dapat diubah adalah sesuatu yang lain daripada konstanta C ++ (ini lebih merupakan tampilan). Tetapi katakanlah, C ++ akan memiliki const secara default, dan varsesuai permintaan hanya menyisakan satu masalah - kedalaman?
greenoldman
1
@ Greenoldman Poin bagus. Sudah lama sejak saya menggunakan C ++ jadi saya lupa Anda dapat memiliki constreferensi ke non- constobjek. Meski begitu, saya tidak percaya itu masuk akal untuk memiliki dangkal const. Inti dari constadalah jaminan bahwa Anda tidak akan dapat mengubah objek melalui referensi itu. Anda tidak boleh mengelak constdengan membuat non- constreferensi, jadi mengapa tidak apa-apa untuk mengelak constdengan memutasikan anggota objek?
Doval
+1 :-) Masalah yang sangat menarik dalam pembaruan Anda (hidup dengan non / const lambdas dan mungkin masalah yang lebih lemah dengan kondisi eksternal), saya harus mencernanya lebih lama. Ngomong-ngomong, untuk komentar Anda, saya tidak memiliki sesuatu yang jahat dalam pikiran - sangat bertentangan, saya mencari fitur untuk meningkatkan kejelasan kode (yang lain: pointer non-nol). Kategori yang sama di sini (setidaknya itu adalah tujuan saya) - Saya mendefinisikan func foo(const String &s)dan ini adalah sinyal yang stidak akan diubah foo.
greenoldman
1
@ greenoldman saya pasti bisa melihat daya tarik dan alasannya. Namun, saya tidak berpikir ada solusi nyata untuk masalah selain menghindari keadaan bisa berubah sebanyak mungkin (bersama dengan hal-hal buruk seperti nulldan pewarisan.)
Doval
8

Masalah utamanya adalah programmer cenderung tidak cukup menggunakannya, jadi ketika mereka menabrak tempat di mana itu diperlukan, atau pengelola kemudian ingin memperbaiki const-correctness, ada efek riak yang besar. Anda masih dapat menulis kode tidak dapat diubah yang sangat baik tanpa const, kompiler Anda tidak akan menegakkannya, dan akan lebih sulit untuk mengoptimalkannya. Beberapa orang lebih suka kompiler mereka daripada membantu mereka. Saya tidak mengerti orang-orang itu, tetapi ada banyak dari mereka.

Dalam bahasa fungsional, hampir semuanya const, dan menjadi bisa berubah adalah pengecualian langka, jika diizinkan sama sekali. Ini memiliki beberapa keuntungan, seperti konkurensi yang lebih mudah dan penalaran yang lebih mudah tentang status bersama, tetapi perlu dibiasakan jika Anda berasal dari bahasa dengan budaya yang bisa berubah. Dengan kata lain, tidak menginginkan constadalah masalah orang, bukan masalah teknis.

Karl Bielefeldt
sumber
+1 terima kasih. Sementara objek yang tidak berubah adalah sesuatu yang lain daripada yang saya cari (Anda dapat membuat objek tidak dapat diubah dalam C # atau Java), bahkan dengan pendekatan tidak berubah Anda harus memutuskan apakah itu dalam atau dangkal, ambil contoh wadah pointer / referensi (dapatkah Anda mengubah nilai objek menjadi titik). Setelah satu hari, tampaknya masalah utamanya adalah apa yang ditetapkan sebagai default, dan mudah dipecahkan saat mendesain bahasa baru.
greenoldman
1
+1 untuk lolz @ "Beberapa orang lebih suka kompiler mereka tidak membantu mereka. Saya tidak mengerti orang-orang itu, tetapi ada banyak dari mereka."
Thomas Eding
6

Saya melihat kekurangannya sebagai:

  • "keracunan const" adalah masalah ketika satu deklarasi const dapat memaksa deklarasi sebelumnya atau berikut untuk menggunakan const, dan itu dapat menyebabkan yang sebelumnya dari deklarasi berikut untuk menggunakan const, dll. Dan jika keracunan const mengalir ke kelas di perpustakaan bahwa Anda tidak memiliki kendali atas, maka Anda bisa terjebak di tempat yang buruk.

  • itu bukan jaminan mutlak. Biasanya ada kasus di mana konst hanya melindungi referensi, tetapi tidak dapat melindungi nilai-nilai yang mendasarinya karena satu dan lain alasan. Bahkan dalam C, ada kasus tepi yang tidak bisa dijangkau oleh const, yang melemahkan janji yang diberikan const.

  • secara umum, sentimen industri tampaknya bergerak menjauh dari jaminan waktu kompilasi yang kuat, betapapun kenyamanan yang mereka dapat berikan kepada Anda dan saya. Jadi untuk sore hari saya habiskan menyentuh 66% basis kode saya karena keracunan const, beberapa Python guy telah menggedor 10 modul Python yang bisa dikerjakan dengan baik, dirancang dengan baik, teruji, berfungsi penuh. Dan dia bahkan tidak meretas ketika dia melakukannya.

Jadi mungkin pertanyaannya adalah, mengapa meneruskan fitur yang berpotensi kontroversial yang bahkan beberapa ahli tidak jelas ketika Anda mencoba untuk mengadopsi bahasa baru Anda yang rumit?

EDIT: jawaban singkat, bahasa baru memiliki bukit yang curam untuk didaki untuk diadopsi. Desainernya benar-benar harus berpikir keras tentang fitur apa yang perlu diadopsi. Ambil Go, misalnya. Google semacam secara brutal memotong beberapa pertempuran agama terdalam dengan membuat beberapa pilihan desain gaya Conan-the-Barbarian, dan saya benar-benar berpikir bahasanya lebih baik untuk itu, dari apa yang saya lihat.

rampok
sumber
2
Peluru kedua Anda tidak benar. Di C ++, ada tiga / empat cara untuk mendeklarasikan referensi / pointer, wrt. constness: int *pointer bisa berubah ke nilai bisa berubah, int const *pointer bisa berubah ke nilai int * constconst , pointer ke nilai bisa berubah, int const * constpointer ke nilai const.
phresnel
Terima kasih. Saya bertanya tentang sifat, bukan pemasaran ("industri menjauh" bukan sifat seperti C ++ const), jadi "alasan" seperti itu saya anggap tidak relevan (setidaknya untuk pertanyaan ini). Tentang constkeracunan - dapatkah Anda memberi contoh? Karena AFAIK adalah keuntungannya, Anda melewatkan sesuatu constdan itu harus tetap const.
greenoldman
1
Ini bukan constmasalah tetapi mengubah tipenya - apa pun yang Anda lakukan, itu akan selalu menjadi masalah. Pertimbangkan untuk lulus RichString, dan kemudian sadarilah Anda untuk lulus dengan lebih baik String.
greenoldman
4
@RobY: Saya tidak yakin dengan siapa / siapa Anda berbicara dengan yang terakhir dan yang sebelumnya . Namun: Setelah sore itu berjalan melalui kode, Anda harus belajar Anda harus refactor untuk benar-benar bottom-up, bukan top-down, yaitu mulai di unit terdalam, dan naik ke atas. Mungkin unit Anda juga tidak cukup terisolasi, bukannya dipasangkan dengan erat, atau Anda telah menjadi mangsa sistem dalam.
phresnel
7
"Keracunan Const" tidak benar-benar masalah - masalah sebenarnya adalah bahwa C ++ default ke non- const. Terlalu mudah untuk tidak melakukan consthal-hal yang seharusnya constkarena Anda harus memilih untuk masuk daripada keluar dari itu.
Doval
0

Ada beberapa masalah filosofis dalam menambah constbahasa. Jika Anda mendeklarasikan constke kelas, itu berarti bahwa kelas tidak dapat berubah. Tetapi kelas adalah seperangkat variabel yang digabungkan dengan metode (atau mutator). Kami mencapai abstraksi dengan menyembunyikan keadaan kelas di balik serangkaian metode. Jika kelas dirancang untuk menyembunyikan negara, maka Anda perlu mutator untuk mengubah keadaan itu dari luar dan kemudian tidak constlagi. Jadi hanya mungkin untuk mendeklarasikan constke kelas yang tidak dapat diubah. Jadi constsepertinya hanya mungkin dalam skenario di mana kelas (atau tipe yang ingin Anda nyatakan const) sepele ...

Jadi, apa kita perlu const? Saya rasa tidak. Saya pikir Anda dapat dengan mudah melakukannya tanpa constmemiliki desain yang bagus. Data apa yang Anda butuhkan dan di mana, metode mana yang merupakan metode data-ke-data dan abstraksi apa yang Anda butuhkan untuk I / O, jaringan, tampilan dll. Kemudian Anda secara alami memecah modul dan kelas muncul yang berhubungan dengan negara dan Anda memiliki metode dan kelas abadi yang tidak membutuhkan status.

Saya pikir sebagian besar masalah muncul dengan objek data besar lemak yang dapat menyimpan, mengubah dan menggambar sendiri dan kemudian Anda ingin meneruskannya ke renderer misalnya. Jadi Anda tidak dapat menyalin isi data, karena itu terlalu mahal untuk objek data besar. Tapi Anda juga tidak ingin itu berubah, jadi Anda perlu sesuatu seperti yang constAnda pikirkan. Biarkan kompiler mencari tahu kekurangan desain Anda. Namun, jika Anda membagi objek-objek itu hanya menjadi objek data yang tidak dapat diubah dan mengimplementasikan metode dalam modul yang bertanggung jawab, Anda dapat mengedarkan (hanya) pointer dan melakukan hal-hal yang ingin Anda lakukan dengan data sambil juga menjamin kekekalan.

Saya tahu bahwa dimungkinkan dalam C ++ untuk mendeklarasikan beberapa metode constdan tidak mendeklarasikan pada metode lain, karena mereka adalah mutator. Dan kemudian beberapa waktu kemudian Anda memerlukan cache dan kemudian pengambil mengubah objek (karena malas memuat) dan tidak constlagi. Tapi itulah inti dari abstraksi ini, kan? Anda tidak tahu status apa yang akan dimutasi dengan setiap panggilan.

Pembuang
sumber
1
"Jadi const tampaknya hanya mungkin dalam skenario di mana kelas (atau tipe yang ingin Anda nyatakan const) sepele ..." Struktur data yang persisten tidak dapat diubah dan non-sepele. Anda tidak akan melihatnya di C ++ karena hampir semua dari mereka membagikan data internal mereka di antara banyak instance, dan C ++ tidak memiliki pengumpulan sampah untuk membuatnya bekerja. "Saya pikir Anda dapat dengan mudah melakukannya tanpa const jika Anda memiliki desain yang bagus." Nilai yang tidak dapat diubah membuat kode lebih mudah untuk dipikirkan.
Doval
+1 terima kasih. Bisakah Anda mengklarifikasi "mendeklarasikan const ke kelas"? Apakah maksud Anda menetapkan kelas sebagai const? Jika ya, saya tidak bertanya tentang ini - C ++ const berfungsi seperti view, Anda dapat mendeklarasikan const di sebelah objek, bukan kelas (atau sesuatu yang berubah di C ++ 11). Juga ada masalah dengan paragraf berikutnya dan kata "mudah" - ada pertanyaan bagus tentang C ++ - const di C # dan jumlah pekerjaan yang terlibat adalah yang terpenting - untuk setiap jenis yang ingin Anda masukkan const(dalam pengertian C ++ ) Anda harus mendefinisikan antarmuka, juga untuk semua properti.
greenoldman
1
Ketika Anda berbicara tentang "kelas" yang Anda maksud sebenarnya adalah "instance dari sebuah kelas", bukan? Saya pikir itu perbedaan penting.
svick