Menggunakan past tense (suara pasif) untuk berkonotasi ketidakberdayaan? (Misalnya, Array. Ditransfer vs. Array. Menentukan)

8

[Catatan: Di bawah ini sedikit C # berat dalam sintaks dan konvensi, seperti mengutip aturan FxCop, karena ini adalah latar belakang saya, tetapi maksud dari diskusi ini adalah untuk menjadi agnostik bahasa dan contoh kode yang digunakan umumnya harus dianggap sebagai kode semu. - Mike]

Saya pikir kita semua akan setuju bahwa kelas umumnya harus dirancang sehingga instance objek mereka tidak berubah di mana pun praktis, dan hasil memanggil anggota kelas harus bebas dari efek samping, sebanyak mungkin.

Akan tetapi, konvensi penamaan historis cenderung menggunakan suara aktif: 'GetSomething', 'DoSomehing', dll. Dan ini bagus karena menyatakan dengan jelas tindakan apa yang akan dilakukan anggota kelas.

Saya sekarang mulai berpikir, bahwa anggota kadang-kadang mungkin (atau mungkin sering) mendapat manfaat dengan disebutkan di masa lalu untuk berkonotasi bahwa nilai dikembalikan tanpa mempengaruhi objek yang direferensikan.

Misalnya, untuk metode yang mentransposkan array, gaya penamaan saat ini mungkin akan menyebutnya 'Array.Transpose', tetapi jika anggota ini mengembalikan array baru , tanpa mentransposisi objek yang direferensikan, maka saya pikir menyebutnya 'Array.Transposed 'Akan lebih akurat dan membuatnya lebih jelas bagi programmer.

Ketika bekerja dengan metode 'Array.Transpose ()' orang mungkin tidak sengaja mencoba menggunakan kode seperti berikut:

Array myArray = new Array(); 
myArray.Transpose();

Tetapi jika metode 'Transpose' mengembalikan array baru tanpa memengaruhi objek yang direferensikan, maka kode ini tidak melakukan apa pun - yaitu, 'myArray' akan diam-diam tidak dipindahkan. (Saya kira jika 'Transpose' adalah properti, maka kompiler akan mengetahui bahwa hal di atas tidak sah, tetapi pedoman FxCop menyatakan bahwa anggota yang melakukan konversi harus menjadi metode.)

Tetapi jika metode ini dinamai dalam bentuk lampau sebagai 'Array.Transposed', akan lebih jelas bagi pengguna bahwa sintaks berikut diperlukan:

Array myArray = new Array(); 
Array transposedArray = myArray.Transposed();

Nama lain yang saya pikir akan masuk dalam kategori ini adalah anggota yang diberi nama 'Resize' vs 'Resize', 'Shifted' vs 'Shift', dll. Present tense akan digunakan untuk anggota yang mempengaruhi objek yang direferensikan, sedangkan past tense akan digunakan untuk anggota yang mengembalikan nilai baru tanpa memengaruhi objek yang direferensikan.

Pendekatan lain yang lebih umum saat ini adalah untuk mengawali setiap nama dengan "Get" atau "To", tapi saya pikir ini menambah bobot yang tidak perlu, sementara mengubah ke past tense mengkomunikasikan artinya secara efektif.

Apakah ini masuk akal bagi programmer lain di sini, atau apakah ide lampau ini terdengar terlalu canggung saat membacanya?

Edit:

Diskusi hebat di bawah ini, saya berterima kasih banyak kepada semua orang. Beberapa poin yang ingin saya rangkum berdasarkan komentar Anda dan pemikiran saya sendiri yang direvisi mengenai hal ini di bawah ini.

Metode Chaining Sintaks "Fasih"

Berdasarkan diskusi di bawah ini, penggunaan past tense mungkin bernilai ketika digunakan pada kelas yang bisa berubah untuk memperjelas anggota mana yang melakukan, atau tidak, mempengaruhi keadaan internal objek yang direferensikan.

Namun, untuk kelas yang tidak berubah, yang seharusnya menjadi mayoritas kasus (orang akan berharap), saya berpikir bahwa penggunaan past tense dapat membuat sintaksisnya menjadi canggung.

Misalnya, dengan "sintaks yang lancar" seperti yang dibuat dengan metode chaining, penggunaan past tense akan membuat kode lebih mudah dibaca. Misalnya, ketika menggunakan LINQ melalui C #, rantai metode yang khas bisa terlihat sebagai berikut:

dataSource.Sort().Take(10).Select(x => x.ToString);

Jika diubah ke bentuk lampau, ini akan menjadi canggung:

dataSource.Sorted().Taken(10).Selected(x => x.ToString);

Ingat, dataSource.Sorted () sebenarnya lebih jelas artinya daripada dataSource.Sort (), karena ekspresi LINQ selalu membuat enumerasi baru tanpa mempengaruhi sumber. Namun, karena kita sepenuhnya menyadari hal ini ketika menggunakan paradigma ini, penggunaan bentuk lampau itu berlebihan dan membuat "kelancaran" membacanya dengan canggung tanpa hasil nyata.

Penggunaan Properti vs. Metode

Masalah utama yang muncul di bawah ini berkaitan dengan pedoman FxCop untuk penggunaan metode "Get" vs. properti read-only. Misalnya, aturan FxCop CA1024 .

Meskipun tidak disebutkan secara eksplisit dalam aturan FxCop itu, penggunaan metode "To" juga berlaku untuk alasan ini, karena metode ToXXXXXX () adalah metode konversi. Dan dalam kasus ToArray (), metode ini adalah metode konversi dan juga metode yang mengembalikan array.

Penggunaan Past Tense untuk Properti Boolean

Beberapa menyarankan bahwa past tense dapat berkonotasi dengan nilai boolean, misalnya properti 'Succeeded' atau 'Connected'. Saya percaya bahwa retort di bawah ini menekankan penggunaan 'Is', 'Has', atau 'Are' untuk properti dan bidang Boolean adalah benar. Past tense dapat membantu dalam hal ini juga, tetapi tidak sebanyak menggunakan awalan 'Is'. Jangan ragu untuk menggunakan bentuk lampau untuk properti dan bidang Boolean, itu memang membantu, tapi saya pikir itu lebih penting untuk mengawali nama dengan 'Is', 'Has', atau 'Are'.

Kesimpulan Keseluruhan?

Untuk masalah Tranpose () vs Transposed (), saya pikir 'skizzy' sudah benar, menyarankan bahwa itu harus Transpose () untuk tindakan bermutasi vs GetTransposed () untuk hasil yang tidak bermutasi. Ini membuatnya 100% jelas. Tapi, sekali lagi, saya pikir ini mungkin hanya berlaku untuk kelas yang berkualitas, seperti array.

Untuk kelas yang tidak dapat diubah, terutama di mana sintaks metode chaining yang lancar dapat digunakan, maka saya berpikir bahwa sintaks ini akan menjadi canggung yang tidak perlu. Sebagai contoh, bandingkan:

var v = myObject.Transpose().Resize(3,5).Shift(2);

untuk:

var v = myObject.GetTransposed().GetResized(3,5).GetShifted(2);

Hmmm ... sebenarnya, bahkan di sini tampaknya membuatnya 100% jelas bahwa hasilnya tidak mempengaruhi sumbernya, tapi saya tidak yakin.

Saya kira untuk paradigma seperti LINQ yang sudah dikenal luas, penggunaan "Get" dan / atau past tense tidak diperlukan, tetapi untuk API baru, mungkin ada nilainya - pada awalnya! Jika API hanya berisi objek yang tidak dapat diubah, setelah pengguna memahami ini, penggunaan "Get" dan / atau past tense hanya akan mengurangi keterbacaan.

Jadi saya pikir tidak ada jawaban yang mudah di sini. Saya kira orang perlu memikirkan keseluruhan API Anda dan memilih dengan hati-hati!

- Mike

Mike Rosenblum
sumber
Saya yakin harap Anda lupa parens untuk pemanggilan metode (atau itu opsional dalam bahasa contohnya, meskipun itu jarang terjadi) dan Anda tidak bermaksud ini menjadi properti ...
Hai delnan, ya, properti dan intensional. Dengan menjadi properti, bahkan lebih jelas bahwa properti 'Transpose' (atau 'Ditransposisikan') mengembalikan nilai dan seharusnya tidak memiliki efek samping. Bahkan, kompiler harus mengambil penggunaan kode yang salah di atas, tetapi ide di sini adalah mencoba untuk menjadi lebih jelas bagi pengguna - sebelum kompilator mengambilnya.
Mike Rosenblum
Saya pikir itu ide yang sangat buruk untuk menggunakan properti untuk semuanya sebagai membuat objek yang sama sekali baru. Dan untuk mendukungnya, MSDN mengatakan metode lebih disukai daripada properti jika "Metode ini melakukan operasi yang memakan waktu. Metode ini terasa lebih lambat daripada waktu yang dibutuhkan untuk mengatur atau mendapatkan nilai bidang."
Sumber yang bagus, terima kasih banyak untuk itu. Jadi contoh 'Transposed' saya mungkin ideal, karena ia melompati aturan FxCop CA1024 karena anggota ini (a) melakukan konversi dan (b) mengembalikan array. Yang mengatakan, diskusi mengenai present vs past tense masih berlaku, tapi saya pasti akan menggunakan metode ToXXXXX () atau GetXXXX () alih-alih properti ketika mengembalikan hasil konversi atau array!
Mike Rosenblum
Saya pikir maksud Anda objek harus abadi, bukan kelas. Kelas umumnya selalu berubah, setidaknya dalam bahasa yang diketik secara statis.
Nemanja Trifunovic

Jawaban:

7

Past-tense agak terdengar canggung. Saya pikir Anda bermaksud kata itu menjadi kata sifat.

Ini saran saya untuk masalah yang Anda minta: alih-alih Transpose(), panggil saja GetTransposed(). Dengan begitu, Anda tahu bahwa Anda menerima sesuatu dan tidak memodifikasi objek.

Sal
sumber
1
Saya pikir, pada akhirnya, bahwa ini sebenarnya jawaban yang "benar". Saya tidak akan menandainya sebagai "benar" karena (1) beberapa orang lain, terutama 'qes' dan 'Developer Art' membuat beberapa komentar yang sangat bijaksana, dan (2) Saya tidak benar-benar berpikir bahwa ada "benar" jawaban untuk ini - ini lebih merupakan pertanyaan "Komunitas Wiki". (Apakah p.se memiliki konsep seperti itu?)
Mike Rosenblum
1
+1 Jawaban singkat yang bagus! Cara Transpose()ini masih bisa diartikan sebagai menyesuaikan objek yang diberikan. Mungkin ini harus menjadi konstruksi bahasa. :) object.Transpose()vs object:Transpose().
Steven Jeuris
Saya lebih AsTransposedsuka daripada GetTransposeduntuk kasus di mana panggilan berulang berulang akan, tanpa efek samping, menghasilkan hasil yang identik secara semantik (yang mungkin atau mungkin bukan objek yang sama, tetapi tidak dapat ditampilkan sebagai objek yang berbeda tanpa menggunakan hal-hal seperti ReferenceEqualsatau yang setara) .
supercat
6

Itu memang masuk akal.

Apa yang Anda bicarakan, menurut pendapat saya, harus diambil sebagai aturan umum saat merancang API atau perpustakaan. Hanya kemudian akan menawarkan manfaat nyata jika sistem ini konsisten di semua kelas.

Masalah lain adalah bahwa dalam banyak kasus, pengguna antarmuka tidak begitu peduli tentang bagaimana hasil dicapai.

Akankah Transpose () memindahkan objek yang sekarang? Akankah Transpose () membuat turunan contoh yang baru dan mengembalikan referensi ke sana? Atau akankah mungkin ditransformasikan satu kali, menyimpan hasil dalam salinan dan mengembalikannya pada panggilan berikutnya tanpa mempengaruhi objek saat ini?

Pengguna sering hanya ingin mendapatkan hasil yang dialihkan, itulah sebabnya tidak banyak yang akan peduli dengan konvensi penamaan yang Anda usulkan.

Tetapi dengan sendirinya, itu adalah proposal yang valid.


sumber
4

Saya sangat tidak setuju. Bentuk lampau canggung dan tidak umum digunakan (yang merupakan alasan cukup untuk tidak memilihnya).

Jika metode ini memodifikasi objek yang dipanggil, ia tidak seharusnya kembali sendiri - ini membuatnya jelas bahwa itu memodifikasi objek.

Demikian juga, jika metode tidak mengubah objek yang dipanggil dan sebagai gantinya membangun objek baru, metode akan mengembalikan objek dengan tipe yang sama. Ini adalah konvensi yang jelas dan sudah umum.

Menurut saya, metode signature adalah konvensi yang lebih jelas dan lebih umum digunakan untuk menunjukkan apakah metode mengembalikan objek baru atau memodifikasi callee.

quentin-starin
sumber
Hai qus, ya, pendekatan lampau tidak umum digunakan, itulah sebabnya saya mengajukan pertanyaan di sini. (Saya pikir itu masuk akal, tetapi preseden sangat penting.) Poin Anda tentang metode tanda tangan adalah bagus, tetapi, sayangnya, adalah yang sangat halus karena kompiler umumnya tidak memaksakan agar hasil dari metode digunakan . Jadi kompiler tidak dapat menangkap kesalahan memanggil myObject.Resize () dan tidak menggunakan nilai pengembalian. Proposal saya adalah bahwa penamaan metode "Resize" akan membuatnya lebih jelas kepada programmer bahwa result = myObject.Resized () diperlukan.
Mike Rosenblum
1
Compiler dapat memperingatkan bahwa hasil dari metode tidak digunakan, yang lebih dari yang dapat mereka lakukan untuk setiap perilaku berdasarkan pada tegang kata kerja dalam bahasa Inggris yang digunakan dalam pengidentifikasi, jadi itu adalah poin yang tidak valid. Saya menyatakan bahwa penamaan dalam bentuk lampau tidak akan membuatnya lebih jelas karena: 1. Ini bukan konvensi yang mapan. 2. Ada konvensi lain yang lebih mapan. 3. Akan ada banyak kata yang akan sangat canggung atau sama sekali tidak valid dalam masa lalu, sedangkan metode tanda tangan tidak akan menderita kebingungan itu.
quentin-starin
Tentu kompiler bisa memperingatkan untuk ini, tetapi mereka umumnya hanya melakukannya untuk properti. Nilai pengembalian dari metode yang tidak digunakan umumnya diabaikan oleh hampir semua kompiler pada pengaturan standar.
Mike Rosenblum
Yang mengatakan, semakin saya memikirkan komentar Anda dan aturan FxCop CA1024 (msdn.microsoft.com/en-us/library/ms182181(VS.80).aspx), contoh saya adalah semua situasi di mana konversi terjadi dan / atau di mana array dikembalikan. Hasilnya adalah ini harus menggunakan penamaan metode GetXXXXX () atau ToXXXXX (), dan saya pikir ini benar. (Terutama karena itu adalah konvensi yang mapan.) Saya pikir penamaan metode dalam pass tense, seperti dalam "GetTransposed ()", masih membantu di sini, tetapi hanya sedikit.
Mike Rosenblum
3

Kedengarannya masuk akal, dan ada preseden - Python memiliki keduanya list.sort()dan sorted(seq). Yang pertama adalah metode, yang lain adalah fungsi yang bekerja pada setiap iterable dan mengembalikan daftar.

Adam Byrtek
sumber
apakah list.sort () mengembalikan sesuatu?
quentin-starin
Tidak, tidak.
Adam Byrtek
2

Di perpustakaan koleksi Scala, ada beberapa metode yang di masa lalu:

  • groupedmengembalikan sebuah iterator yang beralih pada elemen-elemen dari suatu urutan dalam potongan nelemen
  • sorted mengembalikan versi koleksi yang diurutkan
  • updated mengembalikan versi baru koleksi dengan satu elemen berubah

Namun, saya tidak yakin apakah ini keputusan sadar atau apakah mereka kehabisan nama, karena perpustakaan koleksi Scala sangat kaya. Sebagai contoh, ada juga groupBydan sortBymetode, dan updatemetode ini khusus, karena kompiler menulis ulang tugas

foo(bar) = baz

ke

foo.update(bar, baz)

Versi Scala memang melakukan penggunaan updateuntuk koleksi berubah, tetapi memiliki updatekembali versi baru bukan bermutasi sangat canggung, karena Anda jelas harus menetapkan nilai kembali ke sesuatu, jadi misalnya "memperbarui" entri dalam peta abadi akan menjadi sesuatu Suka

val newMap = oldMap(key) = value // HUH ??!!??

Sekarang ya

val newMap = oldMap.updated(key -> value)

Dalam bahasa dengan sistem tipe yang baik, tipe tersebut biasanya akan memberi tahu Anda apakah rutin mengubah mutasi argumennya. Di Haskell, misalnya, tipe dari versi yang tidak dapat diubah adalah sesuatu seperti

transpose :: Array -> Array

sedangkan versi yang bisa berubah akan seperti

transpose :: State Array
Jörg W Mittag
sumber
1

Ketika saya melihat metode / properti dalam bentuk berlalu saya segera menganggap itu mengembalikan boolean. Proposal Anda mungkin masuk akal secara logis, tetapi sepertinya aneh dan canggung. Jika saya harus menjelaskan kepada seseorang mengapa masuk akal itu mungkin bukan konvensi yang baik.

Ed S.
sumber
2
Itu sebabnya itu adalah konvensi yang baik untuk awalan nilai boolean dengan "is". ; p Selanjutnya, alasan dia menjelaskannya adalah karena itu bukan konvensi. Beberapa jawaban untuk pertanyaan ini terlalu mengandalkan konvensi yang ada. Anda harus bisa minggir dan menghakimi tanpa konvensi yang diketahui.
Steven Jeuris
0

Saya bukan penggemar nama variabel masa lampau untuk kekekalan - ini adalah konvensi yang agak tidak biasa dan saya pikir itu akan menyebabkan kebingungan, terutama bagi orang-orang yang tidak terlalu kuat dalam tata bahasa Inggris (dan saya hanya bercanda setengah) sana...)

Juga, konvensi ini menghilangkan peluang menggunakan past tense untuk menunjukkan sesuatu yang lain yang menurut saya lebih penting: deskripsi keadaan objek yang dijelaskan, misalnya "barang yang diproses" dengan jelas memberi tahu Anda bahwa item dalam koleksi sudah diproses, yang merupakan informasi logis penting untuk disampaikan.

Ide yang lebih baik: membuat semuanya tidak berubah . Maka Anda tidak perlu perbedaan bahasa mewah. Anda tahu Anda ingin :-)

mikera
sumber
1
Itu sebabnya itu adalah konvensi yang baik untuk awalan nilai boolean dengan "is" dan "has".
Steven Jeuris