kelas dalam bahasa dan jenis OOP

9

Dalam teori bahasa pemrograman, suatu tipe adalah sekumpulan nilai. Misalnya jenis "int" adalah himpunan semua nilai integer.

Dalam bahasa OOP, kelas adalah tipe, bukan?

Ketika suatu kelas didefinisikan dengan lebih dari satu anggota, mis

class myclass{
    int a; 
    double b;
}

Ketika kita berbicara tentang kelas, maksud kita

  • "Di (a,b)mana aint dan bdobel", atau
  • "{ (x,y)| xapakah ada int, yapakah ada dobel}"?

Apa arti dari instance myclass?

  • "Di (a,b)mana aint dan bdobel", atau
  • sebuah objek yang menempati ruang memori dan yang dapat (tidak harus, yaitu bisa kosong) disimpan (x,y), di mana xada int dan yada yang ganda?
Tim
sumber
2
Kelas adalah tipe. "{(x, y) | x adalah int, y adalah sembarang}" " akan hampir benar, kecuali untuk dua hal: 1) Anda telah menggunakan tuple sementara kelas secara konseptual merupakan catatan - Anda merujuk ke bidang dengan nama, bukan posisi, dan 2) Tidak setiap catatan dengan bidang adan banggota dari jenis itu, seperti yang disebutkan Killian Forth. Myclass isomorfis untuk catatan dengan bidang adan bjenis intdan double- Anda dapat mengambil catatan seperti itu dan mengubahnya menjadi turunan darimyclass
Doval
1
Dalam bahasa yang sangat diketik, kelas adalah tipe. Dalam bahasa yang diketik dengan lemah, ini mungkin atau bukan tipe.
shawnhcorey
1
Dalam teori bahasa pemrograman, tipe adalah seperangkat nilai? Saya pikir Anda perlu membuat sendiri buku lain atau guru lain atau keduanya. 'Variabel' atau 'konstanta' memiliki 'tipe' dan sering memiliki 'nilai'. Ada nol jenis nilai, skalar dan jenis nilai komposit di mana nilai variabel atau konstanta berisi sub-variabel / sub-konstanta.
user1703394
1
@ user1703394 Tipe adalah seperangkat nilai. Tipe integer 32-bit adalah sekumpulan 2 ^ 32 nilai berbeda. Jika ekspresi mengevaluasi ke nilai jenis itu, Anda tahu bahwa nilai ada di set itu. Operator matematika hanya fungsi di atas nilai-nilai set itu.
Doval
1
Saya juga akan berhati-hati mempertimbangkan jenis sebagai set nilai. Set memiliki relasi yang tidak sepenuhnya berlaku untuk tipe. Untuk tipe yang mengkonseptualisasikan, ini adalah model yang baik, tetapi rusak setelah Anda mulai melihat hal-hal lebih dekat - dan bahkan lebih ketika Anda memperkenalkan subtyping.
Telastyn

Jawaban:

30

Tidak juga.

Saya kira Anda bertanya apakah memiliki jenis bidang yang sama sudah cukup untuk diklasifikasikan sebagai kelas yang sama, atau apakah mereka harus dinamai secara identik juga. Jawabannya adalah: "Bahkan tidak memiliki tipe yang sama dan nama yang sama sudah cukup!" Kelas yang secara struktural setara tidak harus kompatibel dengan tipe.

Misalnya, jika Anda memiliki kelas CartesianCoordinatesdan a PolarCordinates, mereka mungkin memiliki dua angka sebagai bidang mereka, dan mereka mungkin bahkan memiliki Numbertipe dan nama yang sama, tetapi mereka masih tidak kompatibel, dan sebuah instance dari PolarCoordinatestidak akan menjadi contoh dari CartesianCoordinates. Kemampuan untuk memisahkan jenis dengan tujuan yang dimaksudkan dan bukan implementasi mereka saat ini adalah bagian yang sangat berguna dari penulisan kode yang lebih aman, lebih dapat dikelola.

Kilian Foth
sumber
9
Perlu dicatat bahwa dalam beberapa bahasa yang setara secara struktural sudah cukup untuk membuat satu jenis subtipe yang lain (dan seringkali sebaliknya). Meskipun itu jelas tidak umum / tidak populer.
Telastyn
7
@Tim Typedef tidak membuat jenis, itu alias nama yang digunakan untuk merujuk ke jenis yang ada.
Doval
1
@DevSolar Dia secara eksplisit menyebutkan C, dan selain C ++, saya tidak tahu bahasa lain yang menggunakan kata kunci itu.
Doval
3
@ Telastyn - bahasa-bahasa itu harus dibunuh dengan api.
Jon Story
4
@JonStory Struktural subtyping berguna pada tingkat modul; kekurangannya adalah apa yang memaksa Anda untuk mengubah semuanya menjadi interfacedi Java dan C # jika Anda ingin melakukan pengujian unit. Anda akhirnya menulis satu ton boilerplate hanya agar Anda dapat mengubah kelas tertentu yang akan digunakan program Anda meskipun Anda tidak memiliki niat untuk mengubahnya saat runtime.
Doval
6

Jenis tidak disetel.

Anda lihat, teori himpunan memiliki sejumlah fitur yang tidak berlaku untuk jenis, dan sebaliknya . Sebagai contoh, suatu objek memiliki tipe kanonik tunggal. Ini mungkin merupakan instance dari beberapa tipe yang berbeda, tetapi hanya salah satu dari tipe tersebut yang digunakan untuk instantiate. Teori himpunan tidak memiliki gagasan tentang perangkat "kanonik".

Teori himpunan memungkinkan Anda membuat himpunan bagian dengan cepat , jika Anda memiliki aturan yang menjelaskan apa yang menjadi bagian dari himpunan bagian. Teori tipe umumnya tidak mengizinkan ini. Sementara sebagian besar bahasa memiliki Numberjenis atau sesuatu yang serupa, mereka tidak memiliki EvenNumberjenis, juga tidak mudah untuk membuatnya. Maksud saya, cukup mudah untuk mendefinisikan tipe itu sendiri, tetapi setiap Numbers yang ada bahkan tidak akan secara ajaib diubah menjadi EvenNumbers.

Sebenarnya, mengatakan bahwa Anda dapat "membuat" himpunan bagian agak tidak jujur, karena himpunan adalah jenis hewan yang berbeda sama sekali. Dalam teori himpunan, himpunan bagian itu sudah ada , dalam semua cara tak terbatas Anda dapat mendefinisikannya. Dalam teori tipe, kita biasanya berharap berhadapan dengan sejumlah tipe yang terbatas (jika besar) pada waktu tertentu. Satu-satunya tipe yang dikatakan ada adalah yang sudah kita tentukan, tidak setiap jenis yang bisa kita definisikan.

Perangkat tidak diizinkan untuk memuat diri mereka secara langsung atau tidak langsung . Beberapa bahasa, seperti Python, menyediakan tipe-tipe dengan struktur yang kurang teratur (dalam Python, typetipe kanoniknya adalah type, dan objectdianggap sebagai turunan dari object). Di sisi lain, sebagian besar bahasa tidak mengizinkan tipe yang ditentukan pengguna untuk terlibat dalam tipu daya semacam ini.

Set biasanya diizinkan untuk tumpang tindih tanpa terkandung satu sama lain. Ini tidak biasa dalam teori tipe, meskipun beberapa bahasa mendukungnya dalam bentuk pewarisan berganda. Bahasa lain, seperti Java, hanya mengizinkan bentuk terbatas ini atau melarangnya sama sekali.

Tipe kosong ada (ini disebut tipe bawah ), tetapi sebagian besar bahasa tidak mendukungnya, atau tidak menganggapnya sebagai tipe kelas satu. "Tipe yang berisi semua tipe lain" juga ada (ini disebut tipe teratas ) dan didukung secara luas, tidak seperti teori himpunan.

NB : Seperti yang ditunjukkan beberapa komentator sebelumnya (sebelum utas dipindahkan ke obrolan), dimungkinkan untuk memodelkan tipe dengan teori himpunan dan konstruksi matematika standar lainnya. Misalnya, Anda bisa memodelkan tipe keanggotaan sebagai relasi daripada memodelkan tipe sebagai set. Namun dalam praktiknya, ini jauh lebih sederhana jika Anda menggunakan teori kategori daripada teori himpunan. Ini adalah contoh bagaimana Haskell memodelkan teori tipenya.


Gagasan "subtyping" benar-benar sangat berbeda dari gagasan "subset." Jika Xini adalah subtipe dari Y, itu berarti kita dapat mengganti instance Yuntuk instance Xdan program akan tetap "berfungsi" dalam beberapa hal. Ini lebih bersifat perilaku daripada struktural, meskipun beberapa bahasa (misalnya Go, Rust, bisa dibilang C) telah memilih yang terakhir karena alasan kenyamanan, baik untuk programmer atau implementasi bahasa.

Kevin
sumber
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
Insinyur Dunia
4

Tipe data aljabar adalah cara untuk membahas hal ini.

Ada tiga cara mendasar yang bisa Anda gabungkan jenis:

  • Produk. Pada dasarnya itulah yang Anda pikirkan:

    struct IntXDouble{
      int a; 
      double b;
    }
    

    adalah jenis produk; nilainya semua kombinasi yang mungkin (yaitu tupel) dari satu intdan satu double. Jika Anda mempertimbangkan tipe angka sebagai set, maka kardinalitas dari tipe produk sebenarnya adalah produk dari kardinalitas field.

  • Jumlah. Dalam bahasa prosedural, ini agak canggung untuk diekspresikan secara langsung (klasiknya dilakukan dengan serikat yang ditandai ), jadi untuk pemahaman yang lebih baik, berikut adalah jenis jumlah di Haskell:

    data IntOrDouble = AnInt Int
                     | ADouble Double
    

    nilai-nilai dari tipe ini memiliki bentuk AnInt 345, atau ADouble 4.23, tetapi selalu ada hanya satu angka yang terlibat (tidak seperti untuk jenis produk, di mana setiap nilai memiliki dua angka). Jadi kardinalitas: pertama-tama Anda menghitung semua Intnilai, masing-masing harus digabungkan dengan AnIntkonstruktor. Plus , semua Doublenilai, masing-masing digabungkan dengan ADouble. Oleh karena itu tipe penjumlahan .

  • Eksponensial 1 . Saya tidak akan membahasnya secara rinci di sini karena tidak memiliki korespondensi OO yang jelas sama sekali.

Jadi bagaimana dengan kelas? Saya sengaja menggunakan kata kunci structalih-alih classuntuk IntXDouble. Masalahnya, kelas sebagai tipe tidak benar-benar ditandai oleh bidangnya, itu hanyalah detail implementasi. Faktor krusialnya adalah, nilai apa yang dapat dibedakan oleh kelas.

Apa yang relevan adalah, nilai suatu kelas dapat menjadi nilai dari semua subkelasnya ! Jadi suatu kelas sebenarnya adalah tipe penjumlahan dari pada tipe produk: jika Adan Bkeduanya berasal myClass, maka myClassdasarnya adalah jumlah dari Adan B. Terlepas dari implementasi yang sebenarnya.


1 Ini fungsi (dalam arti matematika! ); tipe fungsi Int -> Doublediwakili oleh eksponensial DoubleInt. Buruk jika bahasa Anda tidak memiliki fungsi yang tepat ...

leftaroundabout
sumber
2
Maaf, tapi saya pikir ini adalah jawaban yang sangat buruk. Fungsinya memang memiliki analog OO yang jelas, yaitu metode (dan tipe antarmuka metode tunggal). Definisi dasar dari suatu objek adalah objek memiliki status (bidang / anggota data) dan perilaku (metode / fungsi anggota); jawaban Anda mengabaikan yang terakhir.
ruakh
@ruakh: tidak. Anda tentu saja dapat mengimplementasikan fungsi dalam OO, tetapi secara umum, metode bukan fungsi ( karena mereka memodifikasi keadaan dll.). Juga tidak ada "fungsi" dalam fungsi bahasa prosedural, dalam hal ini. Memang, antarmuka metode tunggal statis paling dekat dengan fungsi / tipe eksponensial, tetapi saya berharap untuk menghindari diskusi tentang itu karena tidak memiliki relevansi untuk pertanyaan ini.
leftaroundabout
... yang lebih penting, anwer saya tidak mempertimbangkan perilaku. Memang perilaku biasanya menjadi alasan mengapa Anda menggunakan warisan, dan penyatuan berbagai perilaku yang mungkin tepat menangkap aspek jumlah-jenis kelas OO.
leftaroundabout
@ruakh Metode tidak bisa tanpa objeknya. Analog terdekat adalah staticmetode, kecuali mereka masih bukan nilai kelas satu. Hal tentang kebanyakan bahasa OO adalah bahwa mereka mengambil objek sebagai blok bangunan terkecil, jadi jika Anda ingin sesuatu yang lebih kecil Anda harus memalsukannya dengan objek, dan Anda masih harus menyeret banyak fungsi semantik yang seharusnya tidak dimiliki. Misalnya tidak masuk akal untuk membandingkan fungsi untuk kesetaraan, tetapi Anda masih dapat membandingkan dua objek fungsi palsu.
Doval
@Doval 1) Anda dapat melewati metode di sekitar AFAIK, jadi itu adalah nilai kelas satu; 2) masuk akal untuk membandingkan fungsi untuk kesetaraan, orang JS melakukannya setiap saat.
Den
2

Maaf tapi saya tidak tahu tentang teori "mentah". Saya hanya bisa memberikan pendekatan praktis. Saya harap ini dapat diterima di programer.SE; Saya tidak terbiasa dengan etiket di sini.


Tema sentral OOP adalah menyembunyikan informasi . Apa data anggota suatu kelas, tepatnya, seharusnya tidak menarik bagi kliennya. Seorang klien mengirim pesan ke (memanggil metode / fungsi anggota) sebuah instance, yang mungkin atau mungkin tidak mengubah keadaan internal. Idenya adalah bahwa internal kelas mungkin berubah, tanpa klien terpengaruh olehnya.

Yang perlu diperhatikan adalah bahwa kelas bertanggung jawab untuk memastikan bahwa perwakilan internalnya tetap "valid". Mari kita asumsikan kelas yang menyimpan nomor telepon (disederhanakan) dalam dua bilangan bulat:

    int areacode;
    int number;

Ini adalah data anggota kelas. Namun, kelas mungkin akan lebih dari sekedar anggota datanya, dan tentu saja tidak dapat didefinisikan sebagai "set semua nilai yang mungkin dari int x int". Anda seharusnya tidak memiliki akses langsung ke anggota data.

Konstruksi sebuah instance dapat menolak angka negatif apa pun. Mungkin konstruksi juga akan menormalkan areacode dengan cara tertentu, atau bahkan memverifikasi seluruh nomor. Dengan demikian Anda akan berakhir lebih dekat dengan Anda "(a,b) where a is an int and b is a double", karena tentu saja tidak ada dua int yang disimpan di kelas itu.

Tapi itu tidak terlalu penting sejauh menyangkut kelas. Bukan tipe anggota data, atau rentang nilai yang mungkin yang mendefinisikan kelas, melainkan metode yang ditentukan untuknya.

Selama metode tersebut tetap sama, implementor dapat mengubah tipe data menjadi floating point, BIGNUMs, string, apa pun, dan untuk semua tujuan praktis, itu masih akan menjadi kelas yang sama .


Ada desain patters untuk memastikan bahwa perubahan representasi internal tersebut dapat dilakukan tanpa klien bahkan menyadarinya (misalnya idiom jerawat di C ++, yang menyembunyikan setiap anggota data di belakang pointer buram ).

DevSolar
sumber
1
It is neither the type of the data members, nor the range of their possible values that defines the class, it's the methods that are defined for it.Anggota data tidak mendefinisikan kelas hanya ketika Anda menyembunyikannya. Itu mungkin kasus yang paling umum, tetapi tentu saja tidak dapat dikatakan bahwa itu berlaku untuk semua kelas. Jika bahkan satu bidang bersifat publik, itu sama pentingnya dengan metodenya.
Doval
1
Kecuali jika Anda membuat kode di Java, di mana Anda tidak punya pilihan dalam masalah ini dan bahkan catatan palsu tanpa perilaku bodoh Anda haruslah classes. (Menandai mereka finalmembantu mendapatkan titik, tapi tetap). Anda masih memiliki masalah dengan protectedanggota, yang dapat diwarisi dan dengan demikian membentuk bagian dari API kedua untuk pelaksana subkelas.
Doval
1
@Doval: Saya memahami ini sebagai pertanyaan "teori", oleh karena itu saya menghindari masalah bahasa yang sebenarnya. (Persis seperti saya menjauhi Jawa dan protectedmungkin dalam praktik. ;-))
DevSolar
3
Masalahnya adalah bahwa a classadalah konstruksi yang bergantung pada bahasa. Sejauh yang saya tahu tidak ada yang namanya classteori tipe.
Doval
1
@Doval: Bukankah itu berarti bahwa teori tipe per se tidak berlaku untuk kelas, karena mereka adalah konstruk dari ruang lingkup teori itu?
DevSolar
2
  • Sebuah jenis adalah deskripsi dari kategori / berkisar dari nilai-nilai, struktur senyawa, atau apa pun. Jika demikian, ini mirip dengan "antarmuka". (Dalam pengertian bahasa-agnostik. Bahasa-spesifik, tidak begitu banyak. Di Jawa, misalnya, intadalah tipe , tetapi tidak ada hubungannya dengan interface. Spesifikasi bidang publik / dilindungi, juga, bukan bagian dari interface, tetapi merupakan bagian dari "antarmuka" atau tipe .)

    Poin utamanya adalah, ini lebih merupakan definisi semantik dari pada yang konkret. Struktur hanya faktor karena bidang / perilaku yang terungkap dan tujuan yang ditetapkannya selaras. Jika Anda tidak memiliki keduanya, Anda tidak memiliki kompatibilitas tipe.

  • Sebuah kelas adalah realisasi dari tipe. Ini adalah template yang benar-benar mendefinisikan struktur internal, perilaku terlampir, dll.

cao
sumber