Pemrograman prosedural / fungsional sama sekali tidak lebih lemah dari OOP , bahkan tanpa masuk ke argumen Turing (bahasa saya memiliki kekuatan Turing dan dapat melakukan apa pun yang dilakukan orang lain), yang tidak berarti banyak. Sebenarnya, teknik berorientasi objek pertama kali bereksperimen dalam bahasa yang tidak memilikinya. Dalam hal ini pemrograman OO hanya gaya pemrograman prosedural tertentu . Tapi itu membantu menegakkan disiplin ilmu tertentu, seperti modularitas, abstraksi dan penyembunyian informasi yang penting untuk pemahaman dan pemeliharaan program.
Beberapa paradigma pemrograman berevolusi dari visi teoritis komputasi. Bahasa seperti Lisp berevolusi dari lambda-calculus dan gagasan meta-sirkularitas bahasa (mirip dengan refleksivitas dalam bahasa alami). Klausa klakson yang menjadi ayah dari Prolog dan pemrograman kendala. Keluarga Algol juga berutang pada lambda-calculus, tetapi tanpa refleksivitas bawaan.
Lisp adalah contoh yang menarik, karena telah menjadi ujian bagi banyak inovasi bahasa pemrograman, yang dapat dilacak pada warisan genetik ganda.
Namun bahasa kemudian berkembang, seringkali dengan nama baru. Faktor utama evolusi adalah praktik pemrograman. Pengguna mengidentifikasi praktik pemrograman yang meningkatkan properti program seperti keterbacaan, pemeliharaan, kemampuan kebenaran. Kemudian mereka mencoba untuk menambah fitur atau kendala bahasa yang akan mendukung dan kadang-kadang menegakkan praktik-praktik ini untuk meningkatkan kualitas program.
Artinya , praktik-praktik ini sudah dimungkinkan dalam bahasa pemrograman yang lebih lama, tetapi perlu pemahaman dan disiplin untuk menggunakannya. Memasukkannya ke dalam bahasa baru sebagai konsep utama dengan sintaksis khusus membuat praktik ini lebih mudah digunakan dan mudah dipahami, terutama untuk pengguna yang kurang canggih (yaitu, sebagian besar). Ini juga membuat hidup sedikit lebih mudah bagi pengguna yang canggih.
Dalam beberapa hal, untuk mendesain bahasa apa subprogram / fungsi / prosedur untuk sebuah program. Setelah konsep yang berguna diidentifikasi, diberikan nama (mungkin) dan sintaks, sehingga dapat dengan mudah digunakan dalam semua program yang dikembangkan dengan bahasa itu. Dan ketika berhasil, itu akan dimasukkan dalam bahasa masa depan juga.
Contoh: menciptakan kembali orientasi objek
Saya sekarang mencoba mengilustrasikannya pada sebuah contoh (yang tentunya dapat dipoles lebih lanjut, diberi waktu). Tujuan dari contoh ini bukan untuk menunjukkan bahwa program berorientasi objek dapat ditulis dalam gaya pemrograman prosedural, mungkin dengan mengorbankan kelayakan dan pemeliharaan. Saya lebih suka mencoba untuk menunjukkan bahwa beberapa bahasa tanpa fasilitas OO benar-benar dapat menggunakan fungsi tingkat tinggi dan struktur data untuk benar-benar menciptakan cara untuk meniru secara efektif Orientasi Obyek , untuk mendapatkan manfaat dari kualitasnya mengenai organisasi program, termasuk modularitas, abstraksi dan penyembunyian informasi .
Seperti yang saya katakan, Lisp adalah testbed banyak evolusi bahasa, termasuk paradigma OO (meskipun apa yang bisa dianggap bahasa OO pertama adalah Simula 67, dalam keluarga Algol). Lisp sangat sederhana, dan kode untuk juru bahasa dasarnya kurang dari satu halaman. Tetapi Anda dapat melakukan pemrograman OO di Lisp. Yang Anda butuhkan adalah fungsi urutan yang lebih tinggi.
Saya tidak akan menggunakan sintaks Lisp esoterik, melainkan kode semu, untuk menyederhanakan presentasi. Dan saya akan mempertimbangkan masalah esensial sederhana: menyembunyikan informasi dan modularitas . Mendefinisikan kelas objek sekaligus mencegah pengguna mengakses (sebagian besar) implementasi.
Misalkan saya ingin membuat kelas yang disebut vektor, mewakili vektor 2 dimensi, dengan metode termasuk: penambahan vektor, ukuran vektor, dan paralelisme.
function vectorrec () {
function createrec(x,y) { return [x,y] }
function xcoordrec(v) { return v[0] }
function ycoordrec(v) { return v[1] }
function plusrec (u,v) { return [u[0]+v[0], u[1]+v[1]] }
function sizerec(v) { return sqrt(v[0]*v[0]+v[1]*v[1]) }
function parallelrec(u,v) { return u[0]*v[1]==u[1]*v[0]] }
return [createrec, xcoordrec, ycoordrec, plusrec, sizerec, parallelrec]
}
Kemudian saya dapat menetapkan vektor yang dibuat ke nama fungsi aktual yang akan digunakan.
[vektor, xcoord, ycoord, vplus, vsize, vparallel] = vectorclass ()
Mengapa begitu rumit? Karena saya dapat mendefinisikan dalam fungsi perantara konstruksi vektor yang saya tidak ingin terlihat oleh seluruh program, sehingga dapat mempertahankan modularitas.
Kita dapat membuat koleksi lain dalam koordinat kutub
function vectorpol () {
...
function pluspol (u,v) { ... }
function sizepol (v) { return v[0] }
...
return [createpol, xcoordpol, ycoordpol, pluspol, sizepol, parallelpol]
}
Tapi saya mungkin ingin menggunakan kedua implementasi secara acuh tak acuh. Salah satu cara untuk melakukannya adalah dengan menambahkan komponen tipe ke semua nilai dan mendefinisikan semua fungsi di atas dalam lingkungan yang sama: Kemudian saya dapat mendefinisikan masing-masing fungsi yang dikembalikan sehingga pertama-tama akan menguji jenis koordinat, kemudian menerapkan fungsi spesifik untuk itu.
function vector () {
...
function plusrec (u,v) { ... }
...
function pluspol (u,v) { ... }
...
function plus (u,v) { if u[2]='rec' and v[2]='rec'
then return plusrec (u,v) ... }
return [ ..., plus, ...]
}
Apa yang telah saya peroleh: fungsi spesifik tetap tidak terlihat (karena pelingkupan pengidentifikasi lokal), dan sisanya dari program hanya dapat menggunakan yang paling abstrak yang dikembalikan oleh panggilan ke vectorclass.
Satu keberatan adalah bahwa saya dapat langsung mendefinisikan masing-masing fungsi abstrak dalam program, dan meninggalkan definisi fungsi-fungsi dependen tipe-koordinat. Maka akan disembunyikan juga. Itu benar, tetapi kemudian kode untuk setiap tipe koordinat akan dipotong kecil-kecil tersebar di program, yang kurang dapat diperbaiki dan dipelihara.
Sebenarnya, saya bahkan tidak perlu memberi mereka nama, dan saya hanya bisa menyimpan nilai fungsional sebagai anonim dalam struktur data yang diindeks oleh tipe dan string yang mewakili nama fungsi. Struktur ini menjadi lokal ke vektor fungsi tidak akan terlihat dari sisa program.
Untuk menyederhanakan penggunaan, alih-alih mengembalikan daftar fungsi, saya dapat mengembalikan fungsi tunggal yang disebut apply taking sebagai argumen yang secara eksplisit mengetikkan nilai dan string, dan menerapkan fungsi dengan tipe dan nama yang tepat. Ini sangat mirip dengan memanggil metode untuk kelas OO.
Saya akan berhenti di sini, dalam rekonstruksi fasilitas berorientasi objek ini.
Apa yang saya coba lakukan adalah untuk menunjukkan bahwa tidak terlalu sulit untuk membangun orientasi objek yang dapat digunakan dalam bahasa yang cukup kuat, termasuk warisan dan fitur-fitur lainnya. Metacircularity dari interpreter dapat membantu, tetapi sebagian besar pada tingkat sintaksis, yang masih jauh dari dapat diabaikan.
Pengguna orientasi objek pertama melakukan percobaan konsep seperti itu. Dan itu umumnya benar dari banyak perbaikan pada bahasa pemrograman. Tentu saja, analisis teoretis juga memiliki peran dan membantu memahami atau memperbaiki konsep-konsep ini.
Tetapi gagasan bahwa bahasa yang tidak memiliki fitur OO ditakdirkan untuk gagal di beberapa proyek sama sekali tidak beralasan. Jika perlu, mereka dapat meniru implementasi fitur-fitur ini dengan cukup efektif. Banyak bahasa memiliki kekuatan sintaksis dan semantik untuk melakukan orientasi objek dengan cukup efektif, bahkan ketika itu tidak built-in. Dan itu lebih dari sekadar argumen Turing.
OOP tidak membahas keterbatasan bahasa lain, tetapi mendukung atau menegakkan metodologi pemrograman yang membantu menulis program yang lebih baik, sehingga membantu pengguna yang kurang berpengalaman untuk mengikuti praktik baik yang telah digunakan dan dikembangkan oleh programmer yang lebih maju dan berkembang tanpa dukungan itu.
Saya percaya buku yang bagus untuk memahami semua ini mungkin Abelson & Sussman: struktur dan interpretasi program komputer .