Definisi formal untuk istilah "bahasa OO murni"?


13

Saya tidak bisa memikirkan tempat yang lebih baik di antara saudara kandung untuk mengajukan pertanyaan seperti itu. Awalnya saya ingin bertanya, "Apakah python bahasa OO murni?" tetapi mempertimbangkan masalah dan semacam ketidaknyamanan yang dialami orang saat mencoba mendefinisikan istilah saya memutuskan untuk memulai dengan mendapatkan definisi yang jelas untuk istilah itu sendiri.

Akan lebih adil untuk memulai dengan korespondensi oleh Dr. Alan Kay, yang telah menciptakan istilah (perhatikan inspirasi dalam analogi biologis terhadap sel atau benda hidup lainnya).

Ada beberapa cara berikut untuk mendekati tugas:

  1. Berikan analisis komparatif dengan mendaftarkan bahasa pemrograman yang dapat menunjukkan (atau gagal melakukannya) properti tertentu yang unik dan cukup untuk mendefinisikan istilah (meskipun Smalltalk, Scala, Java , dan sebagainya - adalah contoh yang mungkin tetapi IMO cara ini tampaknya tidak benar-benar lengkap tidak berbuah )
  2. Berikan definisi formal (atau dekat dengan itu, misalnya dalam gaya akademik atau matematika).
  3. Berikan definisi filosofis yang benar-benar akan bergantung pada konteks semantik bahasa konkret atau pengalaman pemrograman apriori (harus ada peluang penjelasan yang berhasil oleh masyarakat).

Versi saya saat ini: "Jika bahasa pemrograman ( formal ) tertentu yang dapat (secara tata bahasa ) membedakan antara operasi dan operan serta menyimpulkan tentang jenis setiap operan apakah jenis ini adalah objek (dalam arti OOP) atau tidak maka kita sebut bahasa seperti itu bahasa OO selama ada setidaknya satu jenis dalam bahasa ini yang merupakan objek. Akhirnya, jika semua jenis bahasa juga objek, kami mendefinisikan bahasa tersebut sebagai bahasa OO murni (kuat). "

Akan menghargai setiap peningkatan yang mungkin terjadi. Seperti yang Anda lihat, saya baru saja membuat definisi bergantung pada istilah "objek" (sering sepenuhnya dirujuk sebagai kelas objek).

[EDIT]

Selain itu, saya menggunakan gagasan (untungnya dipahami dengan baik) tentang jenis seperti dalam bahasa yang diketik. Pemrograman tipe data atau pemrograman berorientasi tipe bukan hanya interpretasi sintaksis (dari teks program, yaitu bagaimana memperlakukan nilai-nilai literal dan variabel data tertentu - sesuatu yang berevolusi menjadi tipe keamanan) tetapi dapat dikaitkan dengan tata bahasa dan dipelajari secara formal (Menggunakan logika matematika) seperti yang disebut sistem tipe . Perhatikan bahwa membutuhkan sistem tipe tertentu untuk memiliki tipe universal yang disebut adalah salah satu cara mendefinisikan kemurnian bahasa OO (ada cara untuk memperluas ini secara semantik).

NB

bagaimana menjawab :

  • ini membantu jika Anda menentukan buku atau referensi yang mendukung / menjelaskan pemahaman Anda tentang terminologi dan konsep (biasanya definisi yang baik mencakup atau referensi semua konsep tergantung kecuali dasar).
  • jika mungkin tunjukkan kategori indentasi dari jawaban / definisi Anda jika tidak jelas sebaliknya (lihat di atas: 1 - dengan contoh bahasa, 2 - logika matematika, 3 - deskripsi teknis dan filosofi pemrograman)
  • Klasifikasi itu penting (dan juga karena istilah pure-OO dimasukkan ke dalam istilah OO) ketika menjawab pertanyaan mencoba untuk mencampur unsur-unsur paradigma OO dari metodologi terkenal lainnya (dan sama sekali tidak membingungkan / tumpang tindih mereka, misalnya biasanya elemen pemrograman modular dapat dibahas. / diwujudkan dengan pemrograman OO): mencoba membedakan OOP dari (termasuk atau menjadi bagian dari) pemrograman fungsional, pemrograman logis (terutama sangat khusus), Jenis Data Abstarct (ADT), Modular, Metaprogramming (generik dan ekspansi-waktu makro LISP), Kontrak (misalnya Eiffel), Berorientasi aspek (AO), (perbedaan antara klasifikasi deklaratif dan fungsional serta definisi historis struktur Dijkstra jelas)

pada kesulitan memberikan definisi formal : cukup mengejutkan sangat mudah untuk memberikan deskripsi matematis tentang OOP dalam bentuk sistem logis (formal) tertentu (berdasarkan tipe yang paling mungkin) dan mendefinisikan satu konsep setelah yang lain. Seseorang bahkan dapat mencoba untuk melakukan sesuatu yang lebih praktis dengan menerapkan formalisme itu untuk mengetik pemeriksaan keselamatan atau aspek desain bahasa baru dari sekadar hiburan atau olahragaabstrak(juga mencari formulasi OOP dalam Teori Tipe Intuitionistic , tipe Dependent , secara mandiri, dalam formalisme FOL sebagai lambda kalkulus dan hanya dengan menggunakan teori kategori). Poin utama di sini adalah tidak mengejutkanformulasi seperti itu IMO sangat bias (cacat) oleh kemungkinan besar pada awalnya tidak lengkap pemahaman tentang OOP (dalam teknik komputer) dan akhirnya menjadi hampir tidak dapat diakses setelah itu (sehingga sulit berkontribusi ke belakang ke dunia pemrograman - mungkin kecuali persentase tertentu menemukan aplikasi kembali dari dunia formal dengan menjadi diintegrasikan ke dalam bahasa populer ).

Jadi ya, sulit untuk memberikan definisi yang "baik", bukan hanya definisi. Tapi saya yakin menanyakan ini di sini karena pengalaman dan keterlibatan langsung Anda, teman-teman.


2
Nah, Anda sudah menjawab sendiri untuk Python. "Tidak".
psr

2
Memberi +1 untuk pertanyaan yang menyenangkan, tetapi versi Anda sedikit cacat oleh masalah bahwa jenis dan objek adalah hal yang berbeda.
Frank

5
@ JoachimSauer: Dia mengatakan dalam surat lain di milis Squeak bahwa "ide besarnya adalah Pesan" dan bahwa dia menyesal pernah menyebutnya "Berorientasi Objek" dan lebih baik menyebutnya "Berorientasi pada Pesan". Erlang, misalnya, adalah bahasa yang berorientasi objek sepenuhnya yang memenuhi semua kriteria Dr. Kay tanpa memiliki konsep sama sekali tentang "objek", "metode", "warisan", "kelas", "prototipe" atau sesuatu seperti itu .
Jörg W Mittag

1
Ini bisa menjadi ilustrasi yang bagus bahwa sintaksis tidak cukup untuk mendefinisikan bahasa OO. Jika seseorang dapat menunjukkan bahwa OOP (misalnya sebagai alat) hanya semantik (sintaksis-independen), itu akan mengubah (membalikkan) pertanyaan saya sepenuhnya!
Yauhen Yakimovich

2
@YauhenYakimovich Ini adalah salah satu masalah utama dalam membahas OOP, semua orang dan anjingnya memiliki ide sendiri tentang apa itu. Sebaliknya, pemrograman terstruktur dan pemrograman fungsional masing-masing dapat didefinisikan dengan sangat sederhana. Hal ini membuat saya mempertanyakan apakah OO memiliki sifat yang mirip dengan agama daripada sains.
Ricky Clarkson

Jawaban:


19

OO, menurut Alan Kay adalah tentang menyampaikan pesan, dan hanya itu. Anda akan melihat bahwa kualitas seperti polimorfisme dan enkapsulasi sebenarnya berasal dari penyampaian pesan.

Sekarang sikap itu sebenarnya sangat ekstrem, karena pada dasarnya berarti hanya Smalltalk dan bahasa yang akan memenuhi syarat.

Saya pikir Anda dapat mendefinisikan OO sebagai membangun sistem Anda pada entitas, yang sepenuhnya merangkum keadaan mereka, dan yang dapat ditukar karena kualitas polimorf yang melekat. Dengan demikian orang dapat berargumen bahasa OO murni memastikan dua kualitas inti ini selalu terpenuhi. Apa yang membuat bahasa OO "tidak murni" akan menjadi mekanisme yang memungkinkan pembuatan konstruk yang tidak memenuhi kriteria ini, seperti kemungkinan untuk:

  • mendeklarasikan bidang publik
  • mendeklarasikan variabel yang hanya dapat menampung instance dari kelas tertentu dan subkelasnya (yaitu variabel harus diketik terhadap antarmuka, yang merupakan objek yang dikomunikasikan benda-benda biologis dalam anologi Kay), yang dirender lebih sempit jika kelas tersebut final, karena yang menyisakan lebih sedikit ruang untuk polimorfisme
  • mendeklarasikan primitif

Kemudian lagi, kemurnian bahasa IMHO lebih merupakan kelemahan daripada kekuatan. OO bukan peluru perak. Tidak ada paradigma tunggal.


2
+1 untuk "OO bukan peluru perak".
Andres F.

1
@AndresF. Perhatikan bahwa nilai praktis OOP serta pengetahuan teoretis lainnya yang terkait dengan pemrograman tidak benar-benar merupakan bagian dari pertanyaan. Sangat jelas bahwa seseorang dapat menulis kode dengan cara yang cukup sukses tanpa pemahaman mendalam tentang teknik atau teori pemrograman (dan sebaliknya). Baik sifat aplikasi dari bahasa OO tidak dibahas, dll.
Yauhen Yakimovich

@YauhenYakimovich Oh, saya tahu. Saya tidak akan mengangkat jawaban jika itu di luar topik. Namun, saya menyukai pernyataan yang saya setujui.
Andres F.

@AndresF. Tentu :-) "OO bukan peluru perak" kemungkinan besar benar dan kami juga tidak memiliki bahasa pemrograman yang sempurna. Tapi apa sebenarnya yang membuat OOP bukan peluru perak? Sama seperti laporan bug yang baik saya pikir terminologi yang rinci dan tepat adalah cara untuk menjawab ini. Saya telah menginvestasikan begitu banyak waktu untuk bekerja dengannya sehingga saya hanya ingin tahu untuk membawanya ke tingkat berikutnya. Apakah OOP hanya sekumpulan ide yang disalin dari satu buku program ke buku lainnya?
Yauhen Yakimovich

@ back2dos +1 untuk secara eksplisit menunjukkan peran "message passing" menurut Kay (Smalltalk, Objective-C). Tampaknya dia tidak pernah bermaksud melihat OOP berkembang ke arah yang dimilikinya saat ini. Tapi saya sangat suka bahwa Kay punya ide untuk membuat objek BUKAN data (tipe). Dia benar-benar mendorong untuk mengaitkannya dengan kualitas biologis, tetapi berakhir dengan "pesan".
Yauhen Yakimovich

6

Saya akan mendekati ini dengan mendefinisikannya sebagai bahasa yang menggunakan konstruksi OOP dan tidak ada yang lain (dengan cara yang sama bahwa bahasa FP murni menggunakan fungsi murni dengan data tidak berubah dan tidak ada yang lain).

Khususnya:

  • Setiap entitas di mana program Anda beroperasi adalah Obyek kelas satu - yaitu tidak ada primitif, tidak ada pointer, tidak ada array dll.
  • Satu-satunya hal yang dapat Anda lakukan dengan objek adalah memanggil metode (berpotensi polimorfik) di atasnya (== mengirim pesan). Tidak ada operasi lain.
  • Semua data dirangkum - yaitu tidak ada akses bidang publik, Anda harus melalui metode pada objek
  • Jika Anda memiliki fungsi kelas pertama maka mereka juga harus menjadi objek - jadi Anda perlu melakukan sesuatu sepertifunctionObject.call(param1,param2)
  • Tidak ada variabel global - jika Anda ingin sesuatu seperti ini, Anda perlu menggunakan objek untuk mewakili lingkungan global saat ini, misalnya environment.getValue("myThing")atau meletakkan variabel dalam objek kelas

Perhatikan bahwa ini masih menyisakan beberapa opsi terbuka:

  • Model objek berbasis kelas vs prototipe
  • Bagaimana warisan diimplementasikan (jika ada)
  • Apakah Anda memiliki metode pengiriman tunggal atau ganda
  • Apakah objek Anda diketik secara statis atau dinamis
  • Sintaks yang tepat digunakan untuk pemanggilan metode (mis. Anda bisa memiliki gula sintaksis untuk getter / setter dll.)

1
ini adalah definisi yang baik, tetapi jangan bingung realitas objek dengan sintaks belaka. Hanya karena fungsi dan variabel global memiliki sintaksis yang ramah, mereka sebenarnya bisa menjadi objek di hati.
ddyer

@ddyer - itu benar jika itu benar-benar hanya sintaks, tapi saya pikir jika sintaks juga memperkenalkan semantik yang berbeda maka dapat merusak "kemurnian". Misalnya, variabel global wrt penggunaan globalVariableNameuntuk mengakses variabel global adalah semantik yang berbeda dari pemanggilan metode pada objek, yang akan menjadi satu-satunya cara untuk mengakses nilai non-lokal di OOP murni.
mikera

Saya pikir "Semuanya" harus memenuhi syarat. Jika suatu bahasa tidak memiliki kemampuan reflektif sama sekali (misalnya, ia tidak dapat mereferensikan metode objek dengan nama abstrak, atau menyimpannya dalam variabel), lalu apakah metode perlu menjadi objek juga? Apakah benda referensi? Apakah referensi dan objek bahkan berbeda?
Joachim Sauer

@ Joachim - poin bagus. Saya memenuhi syarat sebagai "setiap entitas di mana program Anda beroperasi" untuk membedakan objek dari meta-objek dalam bahasa seperti nama variabel dan konstruksi sintaksis. Tentunya jika program Anda benar-benar beroperasi pada hal-hal seperti itu melalui refleksi maka mereka perlu diverifikasi sebagai objek nyata tetapi itu tidak selalu akan menjadi persyaratan. Bagaimanapun, jika Anda dapat memikirkan kualifikasi yang lebih baik, maka silakan mengeditnya!
mikera

"Model objek berbasis kelas vs prototipe": tapi saya akan mengatakan bahwa dalam kedua kasus Anda memiliki semacam klasifikasi, yaitu Anda mengelompokkan objek bersama-sama dengan struktur dan perilaku yang sama.
Giorgio

4

Diskusi tentang apa yang disebut bahasa OO selalu sedikit di sisi otak-dicuci. Yaitu:

"Seseorang mengatakan kepada saya bahwa bahasa X adalah OO, jadi karena itu bahasa X sama dengan OO maka setiap bahasa yang tidak memiliki fitur bahasa X tidak mungkin OO. Dan karena saya menulis kode saya dalam bahasa X, semua yang saya lakukan adalah OO. "

Istilah desain berorientasi objek bermuara pada 3 hal:

  1. Desain modular dengan objek otonom yang tidak tahu informasi tidak perlu tentang sisa program, alias kopling longgar mungkin.
  2. Enkapsulasi data di dalam objek untuk mencegah akses eksternal, baik disengaja dan tidak disengaja.
  3. Ketergantungan yang ditentukan dengan jelas antara objek. Untuk mencapai kopling longgar, tetapi juga untuk membuat program lebih mudah untuk mempertahankan dan memperluas.

1) adalah desain program murni, dapat dicapai dalam bahasa pemrograman apa pun. Namun, beberapa bahasa memiliki fitur bermanfaat seperti kelas / struct dan kata kunci pribadi.

2) terutama desain program, meskipun tidak dapat sepenuhnya dicapai tanpa dukungan bahasa, karena Anda memerlukan mekanisme bahasa seperti privat / statis untuk melindungi dari penggunaan yang tidak disengaja.

3) terutama desain program. Biasanya ada tiga dependensi berbeda: "objek X berisi objek Y", "objek X adalah semacam Y" dan "objek X berinteraksi dengan objek Y". Ada banyak fitur bahasa untuk membantu dengan dependensi ini: warisan / polimorfisme, kelas dasar abstrak dan sebagainya.

Sekarang, jika kita melihat di atas kita dapat melihat bahwa Anda hampir tidak memerlukan fitur bahasa untuk menulis program OO. Fitur-fiturnya hanya membuatnya jauh lebih mudah.

Sasaran di atas tidak dapat dicapai dengan menggunakan beberapa logika berlatar belakang: hanya karena Anda menggunakan kata kunci kelas, program Anda tidak secara otomatis mendapatkan desain modular. Hanya karena Anda menggunakan warisan, itu tidak secara otomatis berarti bahwa dependensi objek Anda masuk akal. Bahasa dengan fitur OO masih memungkinkan hal-hal seperti class TheWholeBloodyProgramatau "Hewan mewarisi Kucing".

Sayangnya, topik desain program berorientasi objek yang baik jarang disebutkan dalam diskusi semacam ini. Programmer yang dicuci otak hanya melihat sintaks dan hal-hal seperti misalnya "C ++ memiliki tipe data primitif sehingga program C ++ Anda bukan OO", lalu mereka menulis program yang benar-benar mengerikan dalam bahasa favorit mereka sendiri, tanpa menggunakan petunjuk apa pun dari desain program apa-begitu-pernah.

Untuk menjawab pertanyaan: sangat sedikit, jika ada bahasa yang memiliki dukungan untuk desain program OO yang tepat. Untuk mengetahui bahasa mana yang memiliki fitur terkait OO tertentu tidak relevan selama programmer tidak tahu apa arti desain berorientasi objek. Seorang programmer yang mengklaim bahwa bahasa-bahasa tertentu berorientasi objek kemungkinan besar tidak memahami konsep OO secara keseluruhan. Tanyakan calon programmer OO bagaimana mereka merancang program OO. Jika hal pertama yang mereka lakukan adalah mulai berteriak kata kunci bahasa, maka Anda dapat dengan aman menganggap mereka tidak tahu desain OO.

Mungkin ada beberapa alat UML-ish mewah tingkat tinggi yang jauh di atas kode sumber mentah, yang memaksa programmer untuk hanya menulis program dengan desain berorientasi objek yang bagus, tapi saya ragu. Alat desain terbaik untuk pemrograman OO kemungkinan besar masih otak manusia dan akal sehat.


Bisakah Anda memperjelas perbedaan definisi Anda, misalnya pemrograman modular dengan tipe data abstrak? Saya pikir Anda berada di jalur yang benar, tetapi saya belum dapat melihat kereta!
Jörg W Mittag

@ JörgWMittag Ini tidak selalu berbeda, ADT tradisional: s dapat ditulis menggunakan desain berorientasi objek, dengan enkapsulasi yang tepat, setter / getter, cara untuk mewarisinya dll dll. Tetapi mereka juga dapat ditulis tanpa memperhatikan desain OO. ->

2
@ JörgWMittag Jika Anda memiliki bahasa seperti C misalnya, dengan dukungan bahasa terbatas untuk OO, maka sulit untuk menulis ADT: s dengan cara yang berorientasi objek. Kesalahan yang paling umum adalah menyerahkan alokasi ADT kepada penelepon, yaitu memberi mereka struktur publik dengan semua internal terpapar, melanggar enkapsulasi. Cara yang tepat untuk melakukan ini dalam C adalah melalui apa yang disebut "tipe buram" (tipe tidak lengkap), meskipun tidak banyak programmer C tahu untuk menggunakannya.

@Lundin: Dalam tulisan yang diposting oleh JörgWMittag sebagai komentar atas jawaban lain, ada (IMO) perbandingan yang menarik antara ADT dan OO.
Giorgio

Saya ingat dari beberapa buku UML (mungkin) poin tambahan 0. Abstrak (menekankan pentingnya formulasi abstrak yang penting untuk hubungan antar-objek seperti polimorfisme, pewarisan, agregasi, dll.).
Yauhen Yakimovich

2

Tidak, tidak ada definisi formal atau bahkan berguna, dan tidak akan pernah ada. Bagi sebagian orang, OOP berarti "kelas dasar Universal" dan "Harus menggunakan semantik referensi, terbaik dengan pengumpul sampah" - dan Anda bahkan bisa mendapatkan pertengkaran tentang sintaks, salah satu hal paling tidak relevan yang pernah ditemukan.

Pada akhirnya, pertama, Anda harus menjawab pertanyaan "Apa itu objek?" Semakin berpikiran sempit akan bersikeras mewarisi dari beberapa kelas dasar universal yang tidak berguna dan tidak perlu dialokasikan pada pemulung untuk memenuhi syarat. Tapi saya lebih suka definisi yang jauh lebih berguna. Tujuan dari OOP adalah untuk memiliki beberapa data, dan beberapa fungsi yang Anda dapat memanggil data itu. Begitu

  • Objek memegang beberapa keadaan dan menawarkan beberapa fungsi pada keadaan itu.

Dalam hal ini, bahkan intmemenuhi syarat. Lagi pula, ketika Anda menulis kode templat dalam C ++ yang dapat menerima primitif atau objek, maka menjadi sulit untuk berpendapat bahwa primitif berbeda dengan cara substansial apa pun. Tidak ada yang berbeda bermakna Vector v1, v2; v1 + v2;daripada int v1, v2; v1 + v2;(kecuali semantik inisialisasi jelek, kita harus mengakui). Juga, ini memungkinkan lambda dan benda-benda semacam itu menjadi objek, karena mereka memegang negara - tangkapan mereka - dan menawarkan fungsi pada negara itu, untuk memanggil lambda.

Untungnya, kita juga dapat mengklasifikasikan pointer ke fungsi bebas sebagai objek, karena keduanya memiliki status (alamat) dan fungsi pada status tersebut (untuk memanggilnya). Jadi fungsi bebas harus diizinkan - bahkan jika Anda mengatakan bahwa semua fungsi bebas sebenarnya adalah pointer fungsi global.


2
Saya melihat tidak perlu perbedaan seperti itu. Tetapi kedua, mereka memiliki identitas yang sama dengan objek lain yang memiliki perbandingan alamat / referensi. Fakta bahwa Anda tidak dapat membedakan dua objek dengan status yang sama, kecuali dengan membandingkan alamat, jauh dari baru dan berlaku untuk semua objek.
DeadMG

5
-1. Mulai dengan kata-kata kasar yang tidak berguna dan tidak perlu, segera beralih ke serangan ad hominem dan satu-satunya hal yang bahkan faktual (definisi OOP ) dari jarak jauh adalah salah. Silakan baca Memahami Abstraksi Data, Diperiksa kembali oleh William R. Cook untuk perbedaan antara Tipe Data Abstrak dan Objek.
Jörg W Mittag

1
"Saya melihat tidak perlu untuk pembedaan seperti itu.": Tapi perbedaan ini adalah salah satu fitur yang diterima secara umum dari objek. Tentu saja, Anda dapat mengembangkan gagasan Anda sendiri tentang suatu objek yang berbeda dari apa yang umumnya diterima. Anda benar-benar bebas melakukannya.
Giorgio

2
@ Jorg aku mohon berbeda. Saya tidak setuju sepenuhnya dengan posting ini tetapi menyebut peringatan di paragraf pertama "tidak berguna" atau "kata-kata kasar" tidak jujur. Tidak ada kesepakatan universal tentang definisi untuk OOP. Itu fakta yang sederhana, dan diakui secara luas. Sisa posting adalah sebuah definisi OOP. Tentu saja bukan yang paling banyak digunakan, atau yang akan saya berikan, tetapi, seperti yang dikatakan DeadMG, sebenarnya cukup berguna.
Konrad Rudolph

2
@KonradRudolph: paragraf yang dibaca sangat berbeda ketika saya menulis komentar saya, termasuk membandingkan programmer yang peduli sintaksis dengan rasis, bahkan menyebutkan pengguna tertentu dari situs ini dengan nama.
Jörg W Mittag

0

Anda dapat memikirkannya dengan contoh negatif. Java bukan bahasa berorientasi objek murni karena ada juga tipe primitif yang bukan objek. Ini adalah bilangan bulat, ganda, array dan sebagainya. Dalam bahasa objek murni, semantik objek tersedia untuk semuanya.

Ada juga pertanyaan tentang seberapa banyak bahasa ditutup untuk modifikasi, bahkan dalam kerangka objek. Di java, Anda tidak bisa mendefinisikan subclass baru untuk beberapa kelas, seperti String atau Kelas.

Bahasa mana yang murni? Satu-satunya kandidat yang muncul dalam pikiran adalah smalltalk.


Bukankah Ruby juga bahasa OO murni?
zxcdw

2
@zxcdw (dan ddyer): itulah masalahnya: tidak ada yang memiliki definisi formal "OO murni", jadi tidak ada yang bisa memberikan jawaban yang pasti untuk pertanyaan itu.
Joachim Sauer
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.