Perbedaan antara tidak berubah dan const

28

Saya sudah sering melihat ketentuan immutabledan constdigunakan secara bergantian. Namun, dari pengalaman (kecil) saya, keduanya sangat berbeda dalam 'kontrak' yang mereka buat dalam kode:

Immutable membuat kontrak bahwa objek ini tidak akan berubah, apa pun (mis. Python tuple, string Java).

Const membuat kontrak bahwa dalam lingkup variabel ini tidak akan diubah (tidak ada janji apa pun tentang apa yang mungkin dilakukan utas lain terhadap objek yang ditunjuk selama periode ini, misalnya kata kunci C / C ++).

Jelas, keduanya tidak setara, kecuali bahasanya adalah single-threaded (PHP), atau memiliki sistem pengetikan linear atau uniquness (Clean, Mercury, ATS).

Pertama, apakah pemahaman saya tentang kedua konsep ini benar?

Kedua, jika ada perbedaan, mengapa mereka hampir secara eksklusif digunakan secara bergantian?

K.Steff
sumber
1
consttidak ada di setiap bahasa, dan ketidakmampuan dan keabadian tidak ada di setiap bahasa sehingga membuat bahasa ini agonistik tidak berlaku. Ini hanya khusus bahasa di mana konsep-konsep ini berlaku.
2
Terkait, bacaan yang disarankan: Jenis Ketidakmampuan (beberapa contoh C #, tetapi sebagian besar bahasa-agnostik). Seseorang memberi Eric Lippert medali.

Jawaban:

14

Saya akan berbicara dengan C ++, di mana perbedaan ini paling relevan.

Seperti yang Anda catat dengan benar, kekekalan berarti bahwa suatu objek tidak dapat berubah sama sekali setelah penciptaannya. Penciptaan ini tentu saja dapat terjadi pada saat runtime, yaitu, suatu constobjek tidak harus berupa konstanta waktu kompilasi. Dalam C ++, objek tidak dapat diubah jika (1) dan (2) atau (3) terpenuhi:

  1. Itu tidak memiliki anggota menyatakan mutableyang dimutasi oleh constfungsi anggota

  2. Dinyatakan const

  3. constfungsi anggota tidak digunakan const_castuntuk menghapus constkualifikasi untuk mengubah anggota mana pun

Namun, Anda juga dapat mempertimbangkan pengubah akses: jika suatu operasi secara internal mengubah sebuah instance, tetapi tidak memiliki efek pada keadaan instance yang dapat diamati melalui antarmuka publiknya, maka objek tersebut “secara logika tidak dapat diubah”.

Jadi C ++ menyediakan alat yang diperlukan untuk membuat objek yang tidak dapat diubah, tetapi seperti kebanyakan semua yang ada di C ++, alat tersebut hanya cukup memadai, dan membutuhkan ketekunan untuk benar-benar menggunakannya. Keadaan instance tidak harus terbatas pada variabel anggota instance — karena C ++ tidak menyediakan cara untuk menegakkan transparansi referensial, ia dapat menyertakan status global atau kelas juga.

constjuga memiliki fungsi lain di C ++: untuk memenuhi syarat referensi dan petunjuk. Sebuah constreferensi dapat merujuk ke non constobjek. Adalah sah (meskipun tidak secara umum tidak perlu atau disarankan) untuk digunakan const_castuntuk memutasi suatu objek melalui constreferensi, jika dan hanya jika objek tersebut dinyatakan non- const:

int        i = 4;         // Non-const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Legal.

Dan tentu saja itu perilaku yang tidak terdefinisi untuk bermutasi constobjek:

const int  i = 4;         // const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Illegal.
Jon Purdy
sumber
19

Berbicara untuk Java di mana kata kunci "final" mewakili "const", pertimbangkan:

final Person someone = new Person();

Ini berarti someoneTIDAK PERNAH bisa merujuk ke objek Orang lain. Namun, Anda masih dapat mengubah detail orang yang dirujuk. Misalnyasomeone.setMonthlySalary(10000);

Tapi, jika someoneitu adalah objek "Immutable", salah satu dari yang berikut ini akan benar: (a) Anda tidak akan memiliki metode bernama setMonthlySalary (b) Memanggil setMonthlySalary akan selalu memberikan pengecualian sepertiUnsupportedOperationException

rasional revolt
sumber
10

Objek yang tidak dapat diubah adalah objek yang tidak mengubah status setelah membuatnya. Sebagai contoh;

string prefix = "Pre";
string postfix = "Post";
string myComplexStr = prefix + postfix;

Dalam contoh ini objek myComplexStr tidak dapat diubah tetapi tidak konstan karena nilainya dihitung. Dan itu tidak berubah karena itu adalah string dan memiliki properti panjang statis dan tidak dapat berubah.

Objek Const umumnya digunakan untuk mengidentifikasi beberapa konstanta nyata yang nilainya diketahui sebelum kompilasi seperti Pi, "USA", "StackOverflow.com", nomor port, dan sebagainya.

Dari perspektif ini, Const berbeda dari objek yang tidak dapat diubah karena nilainya tidak dihitung oleh program.

Tetapi jika Anda berbicara tentang kata kunci "const" di C ++, Anda dapat mengatakan bahwa "const" digunakan untuk membuat objek yang tidak dapat diubah.

Mert Akcakaya
sumber
1
const di C ++ tidak membuat objek yang tidak bisa diubah, itu hanya tingkat akses.
Klaim
Dapatkah Anda menjelaskan bagaimana "const double pi = 3.14" tidak dapat diubah?
Mert Akcakaya
Yah itu tergantung di mana tempatnya. Katakanlah saya lakukan: "double * p_pi = const_cast <double *> (& pi); * p_pi = 42;" sebagai contoh. Kemudian jika pi ada di ruang global atau namespace, saya mendapatkan kesalahan segmentasi, tapi itu, saya percaya, perilaku tidak terdefinisi, bukan kesalahan spesifik. Jika pi adalah anggota dari objek apa pun yang tersedia saat runtime, yang tidak statis, saya mendapatkan pi == 42. Anda lihat, bahkan menggunakan bisa berubah tersedia karena const di C ++ adalah tentang tingkat akses, semantik, bukan data berubah, yang hampir mustahil untuk dicapai di C ++. Anda hanya bisa "mensimulasikan" itu. const tidak bisa berubah.
Klaim
1
@Klaim Mutasi constseperti itu adalah perilaku yang tidak ditentukan di mana pun itu dialokasikan, IIRC. Dan perilaku tidak terdefinisi lebih buruk daripada kesalahan spesifik yang dijamin akan terjadi. Ini berarti Anda tidak menggunakan C ++ lagi - C ++ tidak menyediakan sarana untuk mengubah constnilai (kecuali mutableanggota tentu saja, tetapi itu bukan poin Anda), jadi sejauh menyangkut C ++, Anda tidak dapat melakukannya. Apa implementasi spesifik terjadi untuk memungkinkan adalah masalah lain sepenuhnya (dan saya yakin Anda, jika Anda mengkompilasi dengan optimasi, aksi yang Anda tarik tidak akan mempengaruhi ekspresi yang digunakan nanti pikarena telah diganti).
"const di C ++ tidak membuat objek yang tidak dapat diubah" masih salah karena masih menciptakan konstanta global seperti yang Anda nyatakan dalam jawaban Anda sendiri. Kata kunci tersebut adalah semantik ofcourse pada tingkat tertentu, jika tidak, Anda selalu dapat mengubah tegangan sel memori secara manual dan mengubah nilai objek yang tidak dapat diubah jika Anda ingin sekali bahkan menggunakan perilaku yang tidak terdefinisi.
Mert Akcakaya
8

Pertama, apakah pemahaman saya tentang kedua konsep ini benar?

Ya tetapi pertanyaan kedua Anda menunjukkan bahwa Anda tidak memahami perbedaan-perbedaan ini.

Kedua, jika ada perbedaan, mengapa mereka hampir secara eksklusif digunakan secara bergantian?

constdi C ++ hanya digunakan untuk tingkat akses (itu berarti "read-only") , bukan untuk immutability. Ini menyiratkan bahwa akses itu sendiri benar-benar terpisah dari data. Misalnya Anda dapat memanipulasi beberapa data kemudian memaparkannya melalui referensi const. Aksesnya hanya baca, tetapi datanya sendiri, karena semua datam bisa berubah.

const hanya membatasi akses jaminan, sementara ketidakmampuan (seperti dalam D misalnya) menyiratkan benar-benar tidak ada cara untuk mengubah data pada tahap apa pun dari kehidupan objek .

Sekarang, Anda dapat mensimulasikan imutabilitas dalam C ++ dengan memastikan beberapa data tidak mungkin diakses dengan cara lain selain const dan pastikan itu diinisialisasi kemudian tidak disentuh lagi. Tapi itu bukan jaminan yang kuat karena bahasa seperti D memberi Anda ketika Anda menandai data Anda sebagai tidak dapat diubah. Bahasa memastikan tidak mungkin sama sekali untuk melakukan operasi memodifikasi data itu, sementara di C ++ Anda masih berpotensi untuk mengubah data melalui casting dan mutability const jika benar-benar diperlukan.

Pada akhirnya, itu tidak sama sekali karena tidak menawarkan sama sekali jaminan yang sama.

Klaim
sumber
3

Berbicara tentang JavaScript, kata kunci constdanObject.freeze

constberlaku untuk bindingvariables . Ini menciptakan ikatan yang tidak berubah, Anda tidak dapat menetapkan nilai baru untuk itu.

Object.freezebekerja pada nilai objek. Itu membuat objek tidak berubah . Yaitu, Anda tidak dapat mengubah propertinya.

zangw
sumber
0

Dalam C ++ keduanya sama. Meskipun Anda dapat mengubah constobjek jika Anda memiliki lokasi di memori dan izin OS untuk menulis ke memori itu.

Martin Beckett
sumber
1
Sebenarnya itu argumen melawan mereka menjadi sama: C ++ hanya tidak memiliki kata kunci atau bahasa dukungan abadi. Dan juga, saya berasumsi bahwa programmer menggunakan bahasa secara waras: jika tidak, const juga sama sekali tidak memiliki nilai.
K.Steff
1
@ K.Steff - mungkin lebih baik untuk mengatakan tidak ada kekekalan ekstra dalam C ++ selain yang disediakan oleh const
Martin Beckett
Benar-benar tepat :)
K.Steff
Dalam C ++ mereka tidak sama sekali. const adalah tingkat akses "hanya baca", itu tidak berarti bahwa data tidak dapat diubah. Anda dapat memotongnya di C ++, sebagian besar waktu.
Klaim
0

Dalam C, C ++ dan bahasa terkait, ada juga perbedaan antara objek menjadi const dan referensi Anda atau penunjuk ke objek menjadi referensi konstan.

Jika Anda mencoba untuk memodifikasi objek konstan Anda mendapatkan perilaku yang tidak terdefinisi. (Anda dapat mencoba untuk memodifikasi objek konstan misalnya dengan mengambil alamatnya, melemparkan alamat ke pointer non-const, dan kemudian menggunakan pointer non-const untuk memodifikasi objek).

Pointer atau referensi konstan di sisi lain hanya memberitahu kompiler bahwa Anda tidak dapat menggunakan pointer atau referensi ini untuk memodifikasi objek. Anda dapat melemparkan pointer atau referensi dan mencoba memodifikasi objek. Jika objek itu sendiri konstan, hal-hal buruk akan terjadi. Jika objek tidak benar-benar konstan, itu akan berubah. Ini tentu saja dapat membingungkan pengguna kode Anda dan sangat mungkin menyebabkan bug.

Dalam C, jika Anda menggunakan string literal seperti "Hello", lima karakter dan nol byte trailing sebenarnya konstan, tetapi Anda mendapatkan pointer non-const. Ide yang sangat buruk untuk menggunakan pointer non-const untuk mengubah objek.

Di C, Anda dapat memiliki pointer "constrict". Itu berarti objek yang ditunjuk sementara konstan. Jika objek diubah dengan cara apa pun saat pointer "const membatasi" dalam lingkup, Anda mendapatkan perilaku yang tidak ditentukan. Ini lebih kuat daripada pointer const yang hanya mencegah Anda mengubah objek melalui pointer ini.

gnasher729
sumber