ฉันไม่เข้าใจข้อโต้แย้งกับการใช้งานเกินพิกัด [ปิด]


82

ฉันเพิ่งอ่านหนึ่งในบทความของ Joelที่เขาพูดว่า:

โดยทั่วไปฉันต้องยอมรับว่าฉันกลัวคุณสมบัติภาษาเล็กน้อยที่ซ่อนสิ่งต่างๆ เมื่อคุณเห็นรหัส

i = j * 5;

…อย่างน้อยคุณรู้ไหมว่า j นั้นถูกคูณด้วยห้าและผลลัพธ์ที่เก็บไว้ใน i

แต่ถ้าคุณเห็นตัวอย่างรหัสเดียวกันใน C ++ คุณจะไม่รู้อะไรเลย ไม่มีอะไร วิธีเดียวที่จะรู้ว่าสิ่งที่เกิดขึ้นจริงใน C ++ คือการค้นหาประเภทของฉันและ j คืออะไรบางอย่างที่อาจถูกประกาศในที่อื่นทั้งหมด นั่นเป็นเพราะ j อาจเป็นประเภทที่มีการoperator*ใช้งานมากเกินไปและจะทำสิ่งที่มีไหวพริบมากเมื่อคุณพยายามคูณมัน

(เน้นที่เหมือง) กลัวความสามารถทางภาษาที่ซ่อนสิ่งต่าง ๆ หรือไม่? คุณจะกลัวสิ่งนั้นได้อย่างไร การซ่อนสิ่งต่าง ๆ (หรือที่เรียกว่านามธรรม ) เป็นหนึ่งในแนวคิดหลักของการเขียนโปรแกรมเชิงวัตถุหรือไม่? ทุกครั้งที่คุณเรียกใช้เมธอดa.foo(b)คุณจะไม่มีความคิดว่าจะทำอะไร คุณต้องค้นหาว่าประเภทใดaและbเป็นอะไรบางอย่างที่อาจถูกประกาศในที่อื่นทั้งหมด ดังนั้นเราควรทำอย่างไรกับการเขียนโปรแกรมเชิงวัตถุเพราะมันซ่อนสิ่งต่าง ๆ จากโปรแกรมเมอร์มากเกินไป?

และj * 5แตกต่างจากj.multiply(5)ที่คุณอาจต้องเขียนในภาษาที่ไม่รองรับการบรรทุกเกินพิกัดได้อย่างไร อีกครั้งคุณจะต้องค้นหาประเภทของjและมองเข้าไปในmultiplyวิธีการเพราะแท้จริงและดูเถิดjอาจเป็นประเภทที่มีmultiplyวิธีการที่ทำสิ่งที่มีไหวพริบมาก

"Muahaha ฉันเป็นนักเขียนโปรแกรมที่ชั่วร้ายที่ตั้งชื่อวิธีการmultiplyแต่สิ่งที่จริง ๆ แล้วมันคือความคลุมเครือและไม่เข้าใจสัญชาตญาณโดยสิ้นเชิง นั่นเป็นสถานการณ์ที่เราต้องพิจารณาเมื่อออกแบบภาษาการเขียนโปรแกรมหรือไม่? จากนั้นเราต้องละทิ้งตัวระบุจากภาษาการเขียนโปรแกรมโดยอ้างว่าอาจทำให้เข้าใจผิด!

หากคุณต้องการทราบว่าวิธีการใดที่คุณสามารถทำได้อย่างรวดเร็วสามารถดูได้ที่เอกสารประกอบหรือมองเข้าไปในการนำไปใช้ ผู้ประกอบการมากไปเป็นน้ำตาลเชิงประโยคและฉันไม่เห็นว่ามันจะเปลี่ยนเกมได้อย่างไร

โปรดให้ความกระจ่างแก่ฉัน


20
+1: เขียนได้ดีมีการถกเถียงกันมากหัวข้อที่น่าสนใจและเป็นที่ถกเถียงกันอย่างมาก ตัวอย่างที่ส่องแสงของคำถาม p.se
Allon Guralnek

19
+1: ผู้คนฟัง Joel Spolsky เพราะเขาเขียนได้ดีและเป็นที่รู้จักกันดี แต่นั่นไม่ได้ทำให้เขาถูกต้อง 100% ของเวลา ฉันเห็นด้วยกับข้อโต้แย้งของคุณ หากเราทุกคนปฏิบัติตามตรรกะของโจเอลที่นี่เราจะไม่ไปไหนเลย
ไม่มีใคร

5
ฉันยืนยันว่า i และ j ถูกประกาศแบบโลคัลเพื่อให้คุณสามารถดูประเภทของมันได้อย่างรวดเร็วหรือพวกมันชื่อตัวแปรที่น่าเบื่อและควรเปลี่ยนชื่ออย่างเหมาะสม
Cameron MacFarland

5
+1 แต่อย่าลืมส่วนที่ดีที่สุดของบทความของโจเอล: หลังจากวิ่งมาราธอนเพื่อหาคำตอบที่ถูกต้องเขาไม่มีเหตุผลชัดเจนที่จะหยุดยั้งความยาว 50 ฟุต รหัสผิดไม่ควรดูผิด มันไม่ควรรวบรวม
Larry Coleman

3
@ Larry: คุณสามารถสร้างรหัสผิดพลาดในการคอมไพล์โดยการกำหนดคลาสอย่างเหมาะสมดังนั้นในตัวอย่างของเขาคุณสามารถมี SafeString และ UnsafeString ใน C ++ หรือ RowIndex และ ColumnIndex แต่คุณต้องใช้ตัวดำเนินการ overloading เพื่อทำให้พวกเขาทำงานได้อย่างสังหรณ์ใจ
David Thornley

คำตอบ:


32

รหัส 'ซ่อน' สิ่งที่เป็นนามธรรมเพื่อให้คุณไม่ต้องกังวลเกี่ยวกับการทำงานภายในและบ่อยครั้งที่คุณไม่สามารถเปลี่ยนได้ แต่เจตนาไม่ได้ขัดขวางไม่ให้คุณมองมัน เราเพิ่งตั้งสมมติฐานเกี่ยวกับผู้ให้บริการและอย่างที่โจเอลกล่าวว่าอาจเป็นที่ใดก็ได้ การมีคุณสมบัติการเขียนโปรแกรมที่ต้องการให้ตัวดำเนินการที่โอเวอร์โหลดทั้งหมดถูกสร้างขึ้นในตำแหน่งเฉพาะอาจช่วยในการค้นหา แต่ฉันไม่แน่ใจว่ามันจะทำให้การใช้งานนั้นง่ายขึ้นได้อย่างไร

ฉันไม่เห็นการสร้าง * ทำสิ่งที่ไม่คล้ายกับการคูณดีกว่าฟังก์ชั่นที่เรียกว่า Get_Some_Data ที่ลบข้อมูล


13
+1 สำหรับบิต 'ฉันไม่เห็น' มีคุณสมบัติภาษาสำหรับการใช้งานไม่ละเมิด
Michael K

5
แต่เรามี<<โอเปอเรเตอร์ที่กำหนดไว้ในสตรีมซึ่งไม่มีส่วนเกี่ยวข้องกับการเปลี่ยนบิตบิตในไลบรารีมาตรฐานของ C ++
Malcolm

ตัวดำเนินการ 'bitwise shift' ถูกเรียกเท่านั้นเพื่อเหตุผลทางประวัติศาสตร์ เมื่อนำไปใช้กับประเภทมาตรฐานมันจะทำการปรับระดับบิตในลักษณะเดียวกับที่ผู้ประกอบการ + เพิ่มตัวเลขเข้าด้วยกันเมื่อนำไปใช้กับประเภทตัวเลขอย่างไรก็ตามเมื่อนำไปใช้กับประเภทที่ซับซ้อนจะสามารถทำสิ่งที่ชอบได้ตราบใดที่มัน ความรู้สึกสำหรับประเภทนั้น
gbjbaanb

1
* ยังใช้สำหรับการยกเลิกการอ้างอิง (เช่นเดียวกับตัวชี้สมาร์ทและตัววนซ้ำ) ยังไม่ชัดเจนว่าจะให้แบ่งขอบเขตระหว่างการบรรทุกเกินพิกัดที่ดีและไม่ดีอย่างไร
martinkunev

มันจะไม่อยู่ที่ใดเลยมันจะอยู่ในนิยามประเภทของ j
แอนดี้

19

IMHO คุณสมบัติด้านภาษาเช่นการใช้งานเกินกำลังทำให้โปรแกรมเมอร์มีกำลังมากขึ้น และอย่างที่เรารู้ด้วยพลังอันยิ่งใหญ่มาพร้อมความรับผิดชอบที่ยิ่งใหญ่ ฟีเจอร์ที่ให้พลังมากขึ้นช่วยให้คุณมีวิธียิงตัวเองมากขึ้นและแน่นอนว่าควรใช้อย่างรอบคอบ

ยกตัวอย่างเช่นมันทำให้รู้สึกดีที่จะเกิน+หรือ*ผู้ประกอบการสำหรับการหรือclass Matrix class Complexทุกคนจะรู้ทันทีว่ามันหมายถึงอะไร ในทางตรงกันข้ามสำหรับฉันความจริงที่ว่า+หมายถึงการรวมกันของสตริงไม่ชัดเจนแม้ Java ทำสิ่งนี้เป็นส่วนหนึ่งของภาษาและ STL std::stringใช้สำหรับการใช้งานตัวดำเนินการมากเกินไป

อีกตัวอย่างที่ดีเมื่อตัวดำเนินการโอเวอร์โหลดทำให้โค้ดชัดเจนมากขึ้นคือตัวชี้อัจฉริยะใน C ++ คุณต้องการให้สมาร์ทพอยน์เตอร์ทำตัวเหมือนพอยน์เตอร์ทั่วไปให้มากที่สุดเท่าที่จะเป็นไปได้ดังนั้นจึงเหมาะสมอย่างยิ่งที่จะโอเวอร์โหลดยูนิเวอร์แซล*และ->โอเปอเรเตอร์

ในสาระสำคัญผู้ประกอบการมากไปไม่มีอะไรมากไปกว่าการตั้งชื่อฟังก์ชั่นอื่น และมีกฎสำหรับการตั้งชื่อฟังก์ชั่น: ชื่อต้องเป็นคำอธิบายทำให้ชัดเจนทันทีว่าฟังก์ชันทำอะไร กฎที่แน่นอนเดียวกันนี้นำไปใช้กับผู้ปฏิบัติงานมากไป


1
สองประโยคสุดท้ายของคุณคือหัวใจของการคัดค้านการดำเนินการมากไป: ความปรารถนาสำหรับโค้ดทั้งหมดจะชัดเจนทันที
Larry Coleman

2
ไม่ชัดเจนว่า M * N หมายถึงที่ M และ N เป็นประเภทเมทริกซ์หรือไม่
Dima

2
@ เฟร็ด: ไม่ มีการคูณเมทริกซ์หนึ่งชนิด คุณสามารถคูณเมทริกซ์ mxn ด้วยเมทริกซ์ nxk และรับเมทริกซ์ mxk
Dima

1
@FredOverflow: มีวิธีที่แตกต่างกันในการคูณเวกเตอร์สามมิติหนึ่งอันให้สเกลาร์กับคุณและอีกหนึ่งให้เวกเตอร์สามมิติอีกอันหนึ่งและการบรรทุกเกินพิกัด*สำหรับคนเหล่านั้นอาจทำให้เกิดความสับสน เนื้อหาที่คุณสามารถใช้operator*()สำหรับผลิตภัณฑ์ดอทและoperator%()สำหรับผลิตภัณฑ์ครอส แต่ฉันจะไม่ทำเช่นนั้นสำหรับห้องสมุดที่ใช้งานทั่วไป
David Thornley

2
@Martin Beckett: ไม่อนุญาตให้ลำดับ C ++ เรียงลำดับใหม่A-BอีกB-Aครั้งและตัวดำเนินการทั้งหมดเป็นไปตามรูปแบบดังกล่าว แม้ว่าจะมีข้อยกเว้นหนึ่งข้ออยู่เสมอ: เมื่อคอมไพเลอร์สามารถพิสูจน์ได้ว่ามันไม่สำคัญมันก็ได้รับอนุญาตให้จัดเรียงใหม่ทุกอย่าง
Sjoerd

9

ใน Haskell "+", "-", "*", "/" ฯลฯ เป็นเพียงฟังก์ชั่น (ใส่)

คุณควรตั้งชื่อฟังก์ชั่น infix "plus" ใน "4 plus 2" หรือไม่? ทำไมไม่ถ้าเพิ่มเป็นสิ่งที่ฟังก์ชั่นของคุณ คุณควรตั้งชื่อ "plus" function "+" หรือไม่? ทำไมจะไม่ล่ะ.

ฉันคิดว่าปัญหาที่เรียกว่า "โอเปอเรเตอร์" คือพวกเขาส่วนใหญ่คล้ายกับการดำเนินการทางคณิตศาสตร์และมีหลายวิธีที่จะตีความสิ่งเหล่านั้นไม่ได้ดังนั้นจึงมีความคาดหวังสูงเกี่ยวกับวิธี / ฟังก์ชัน / โอเปอเรเตอร์

แก้ไข: ทำให้จุดของฉันชัดเจนยิ่งขึ้น


เอ่อยกเว้นสิ่งที่สืบทอดมาจาก C, C ++ (และนั่นคือสิ่งที่เฟร็ดถาม) ทำในสิ่งเดียวกัน ทีนี้คุณคิดว่าอะไรดีหรือไม่ดี?
sbi

@sbi ฉันรักมากไปประกอบการ ... ผู้ประกอบการจริงแม้ C ได้มากเกินไป ... ท่านสามารถใช้พวกเขาสำหรับint, float, long longและสิ่ง แล้วมันเกี่ยวกับอะไร?
FUZxxl

@FUZxxl: นี่คือทั้งหมดที่เกี่ยวกับผู้ประกอบการที่กำหนดโดยผู้ใช้มากเกินไปคนในตัว
sbi

1
@sbi Haskell มีความแตกต่างระหว่างไม่มีbuiltinและผู้ใช้กำหนด ผู้ประกอบการทั้งหมดมีค่าเท่ากัน คุณสามารถเปิดส่วนขยายบางส่วนเพื่อลบสิ่งที่กำหนดไว้ล่วงหน้าทั้งหมดและให้คุณเขียนอะไรก็ได้ตั้งแต่ต้นรวมถึงตัวดำเนินการใด ๆ
FUZxxl

@FUZxxl: นั่นอาจเป็นไปได้ แต่ผู้ปฏิบัติงานที่มีการโอเวอร์โหลดมักจะไม่คัดค้านการใช้บิวด์อิน+สำหรับประเภทตัวเลขในตัวที่แตกต่างกัน แต่สร้างโอเวอร์โหลดที่ผู้ใช้กำหนดเอง ดังนั้นความคิดเห็นของฉัน
sbi

7

จากคำตอบอื่น ๆ ที่ฉันเคยเห็นฉันสามารถสรุปได้ว่าการคัดค้านการใช้งานเกินจริงเป็นความต้องการโค้ดที่ชัดเจนในทันที

นี่เป็นเรื่องน่าเศร้าด้วยเหตุผลสองประการ:

  1. ด้วยข้อสรุปเชิงตรรกะหลักการที่ว่าโค้ดควรจะชัดเจนในทันทีจะทำให้เราทุกคนยังคงเขียนโค้ดในภาษาโคบอล
  2. คุณไม่ได้เรียนรู้จากโค้ดที่ชัดเจนทันที คุณเรียนรู้จากโค้ดที่สมเหตุสมผลเมื่อคุณใช้เวลาคิดเกี่ยวกับวิธีการทำงาน

การเรียนรู้จากโค้ดนั้นไม่ได้มีวัตถุประสงค์หลักเสมอไป ในกรณีเช่น "ฟีเจอร์ X กำลังกระตุกผู้ที่เขียนมันออกจาก บริษัท และคุณจำเป็นต้องแก้ไขโดยเร็ว" ฉันจะค่อนข้างมีโค้ดที่ชัดเจนทันที
ข้อผิดพลาด

5

ฉันค่อนข้างเห็นด้วย

ถ้าคุณเขียนmultiply(j,5), jอาจจะเป็นของสเกลาหรือเมทริกซ์ชนิดทำmultiply()มากหรือน้อยกว่าที่ซับซ้อนขึ้นอยู่กับสิ่งที่jเป็น อย่างไรก็ตามหากคุณละทิ้งแนวคิดเรื่องการโอเวอร์โหลดไปพร้อม ๆ กันฟังก์ชั่นจะต้องตั้งชื่อmultiply_scalar()หรือmultiply_matrix()ทำให้ชัดเจนว่าเกิดอะไรขึ้นภายใต้

มีรหัสที่พวกเราหลายคนชอบมันแบบทางเดียวและมีรหัสที่พวกเราส่วนใหญ่จะชอบอีกทางหนึ่ง อย่างไรก็ตามรหัสส่วนใหญ่ตกลงไปที่พื้นกลางระหว่างสองขั้วต่อสุดขั้วเหล่านั้น สิ่งที่คุณต้องการขึ้นอยู่กับพื้นหลังและความชอบส่วนตัวของคุณ


จุดดี. อย่างไรก็ตามการทิ้งการโหลดเกินพิกัดไปด้วยกันไม่ได้ดีนักกับการเขียนโปรแกรมทั่วไป ...
fredoverflow

@FredO: ไม่แน่นอน แต่การเขียนโปรแกรมทั่วไปนั้นเกี่ยวกับการใช้อัลกอริทึมเดียวกันสำหรับประเภทที่แตกต่างกันมากดังนั้นผู้ที่เลือกmultiply_matrix()จะไม่ชอบการเขียนโปรแกรมทั่วไป
sbi

2
คุณค่อนข้างจะมองโลกในแง่ดีเกี่ยวกับชื่อใช่มั้ย จากบางสถานที่ที่ฉันทำงานฉันคาดหวังว่าชื่อเช่น 'multiply ()' และ 'multiplym ()' หรืออาจจะreal_multiply()มากกว่านั้น นักพัฒนามักจะไม่ค่อยดีกับชื่อและoperator*()อย่างน้อยก็จะสอดคล้องกัน
David Thornley

@ David: ใช่ฉันข้ามความจริงที่ว่าชื่ออาจไม่ดี แต่จากนั้นเราอาจจะคิดว่าoperator*()อาจทำอะไรโง่ ๆ ได้เช่นกันjคือมาโครที่ประเมินถึงนิพจน์ที่เกี่ยวข้องกับการเรียกใช้ฟังก์ชันห้าครั้งและอะไรก็ตาม จากนั้นคุณไม่สามารถเปรียบเทียบทั้งสองแนวทางได้แล้ว แต่ใช่การตั้งชื่อสิ่งต่าง ๆ ได้ยากแม้จะคุ้มค่ากับเวลาก็ตาม
sbi

5
@ David: และเนื่องจากการตั้งชื่อสิ่งที่ยากชื่อควรถูกเนรเทศจากภาษาการเขียนโปรแกรมใช่มั้ย มันง่ายเกินไปที่จะทำความผิด! ;-)
fredoverflow

4

ฉันเห็นปัญหาสองข้อเกี่ยวกับการใช้งานมากเกินไป

  1. การโหลดมากเกินไปจะเปลี่ยนซีแมนติกส์ของโอเปอเรเตอร์แม้ว่าโปรแกรมเมอร์จะไม่ได้ตั้งใจก็ตาม ตัวอย่างเช่นเมื่อคุณเกิน&&, ||หรือ,คุณจะสูญเสียจุดลำดับที่ส่อให้เห็นถึงตัวในสายพันธุ์ของผู้ประกอบการเหล่านี้ (เช่นเดียวกับพฤติกรรมการลัดวงจรของผู้ประกอบการลอจิคัล) ด้วยเหตุนี้จึงเป็นการดีกว่าที่จะไม่ใช้ตัวดำเนินการเหล่านี้มากเกินไปแม้ว่าภาษาจะอนุญาตก็ตาม
  2. บางคนเห็นว่าการใช้งานมากเกินไปเป็นคุณสมบัติที่ดีพวกเขาเริ่มใช้งานได้ทุกที่แม้ว่าจะไม่ใช่โซลูชันที่เหมาะสม สิ่งนี้ทำให้คนอื่น ๆ ทำปฏิกิริยามากเกินไปในทิศทางอื่นและเตือนการใช้งานตัวดำเนินการมากไป ฉันไม่เห็นด้วยกับทั้งสองกลุ่ม แต่คำนึงถึงจุดกึ่งกลาง: การใช้งานมากเกินไปควรใช้อย่าง จำกัด และเฉพาะเมื่อ
    • ตัวดำเนินการที่โอเวอร์โหลดมีความหมายตามธรรมชาติสำหรับทั้งผู้เชี่ยวชาญด้านโดเมนและผู้เชี่ยวชาญด้านซอฟต์แวร์ หากทั้งสองกลุ่มไม่เห็นด้วยกับความหมายตามธรรมชาติของผู้ปฏิบัติงานอย่าทำเกินความจำเป็น
    • สำหรับประเภทที่เกี่ยวข้องไม่มีความหมายตามธรรมชาติสำหรับผู้ปฏิบัติงานและบริบททันที (โดยเฉพาะการแสดงออกที่เหมือนกัน แต่ไม่เกินสองสามบรรทัด) ทำให้ชัดเจนเสมอว่าความหมายของตัวดำเนินการคืออะไร ตัวอย่างของหมวดหมู่นี้operator<<สำหรับสตรีม

1
+1 จากฉัน แต่อาร์กิวเมนต์ที่สองสามารถนำไปใช้กับมรดกได้อย่างเท่าเทียมกัน หลายคนไม่มีเงื่อนงำเกี่ยวกับการสืบทอดและพยายามนำไปใช้กับทุกสิ่ง ฉันคิดว่าโปรแกรมเมอร์ส่วนใหญ่จะยอมรับว่าเป็นไปได้ที่จะใช้มรดกอย่างไม่ถูกต้อง นั่นหมายความว่าการสืบทอดนั้นเป็น "ความชั่วร้าย" และควรถูกทอดทิ้งจากภาษาการเขียนโปรแกรมหรือไม่? หรือเราควรทิ้งไว้เพราะมันก็มีประโยชน์เช่นกัน?
fredoverflow

@FredOverflow อาร์กิวเมนต์ที่สองสามารถนำไปใช้กับสิ่งที่เป็น "ใหม่และร้อน" ฉันไม่ได้ให้เป็นข้อโต้แย้งในการลบโอเปอเรเตอร์ที่บรรทุกเกินพิกัดจากภาษา แต่เป็นเหตุผลว่าทำไมคนจึงโต้แย้งกับมัน เท่าที่ฉันมีความกังวลการบรรทุกเกินพิกัดมีประโยชน์ แต่ควรใช้ด้วยความระมัดระวัง
Bart van Ingen Schenau

IMHO การอนุญาตให้มีการโอเวอร์โหลดของ&&และ||ในลักษณะที่ไม่ได้หมายความว่าการเรียงลำดับนั้นเป็นความผิดพลาดครั้งใหญ่ (IMHO หาก C ++ กำลังจะอนุญาตการโอเวอร์โหลดของไฟล์เหล่านั้นควรใช้รูปแบบ "สองฟังก์ชัน" พิเศษโดยจำเป็นต้องมีฟังก์ชันแรก เพื่อคืนค่าชนิดที่ถูกแปลงโดยปริยายให้เป็นจำนวนเต็มฟังก์ชันที่สองอาจใช้อาร์กิวเมนต์สองหรือสามอาร์กิวเมนต์โดยมีอาร์กิวเมนต์ "พิเศษ" ของฟังก์ชันที่สองเป็นชนิดส่งคืนของแรกคอมไพเลอร์จะเรียกใช้ฟังก์ชันแรกจากนั้น ถ้ามันกลับไม่ใช่ศูนย์ประเมินผลการดำเนินสองและเรียกใช้ฟังก์ชันที่สองกับมัน).
SuperCat

แน่นอนว่ามันไม่น่าประหลาดใจเท่าที่จะอนุญาตให้ผู้ใช้งานคอมม่าโอเวอร์โหลด อนึ่งสิ่งที่มากไป - ish ฉันไม่ได้เห็นจริง ๆ แต่อยากจะเป็นวิธีการเข้าถึงสมาชิกที่มีผลผูกพันทำให้การแสดงออกชอบที่foo.bar[3].Xจะได้รับการจัดการในfooชั้นเรียนของมากกว่าที่fooจะต้องเปิดเผยสมาชิกที่ สามารถรองรับ subscripting Xแล้วสัมผัสได้เป็นสมาชิก ((foo.bar)[3]).Xหากใครต้องการที่จะบังคับให้ประเมินผ่านการเข้าถึงสมาชิกที่เกิดขึ้นจริงอย่างใดอย่างหนึ่งจะเขียน
supercat

3

จากประสบการณ์ส่วนตัวของฉันวิธี Java ของการอนุญาตให้มีหลายวิธี แต่ไม่รวมตัวดำเนินการมากเกินไปหมายความว่าเมื่อใดก็ตามที่คุณเห็นผู้ดำเนินการที่คุณรู้ว่ามันทำอะไร

คุณไม่จำเป็นต้องดูว่า*จะเรียกใช้โค้ดแปลก ๆ หรือไม่ แต่รู้ว่ามันคือการคูณและมันจะทำงานเหมือนกันตามวิธีที่กำหนดโดย Java Language Specification ซึ่งหมายความว่าคุณสามารถมุ่งความสนใจไปที่พฤติกรรมจริงแทนที่จะค้นหาสิ่งต่าง ๆ ที่กำหนดโดยโปรแกรมเมอร์

กล่าวอีกนัยหนึ่งการห้ามผู้ปฏิบัติงานโอเวอร์โหลดเป็นประโยชน์ต่อผู้อ่านไม่ใช่นักเขียนและทำให้โปรแกรมง่ายต่อการบำรุงรักษา!


+1 โดยมีข้อแม้: C ++ ให้เชือกพอที่จะแขวนตัวเอง แต่ถ้าฉันต้องการใช้รายการที่ลิงก์ใน C ++ ฉันต้องการความสามารถในการใช้ [] เพื่อเข้าถึงองค์ประกอบที่ n มันสมเหตุสมผลที่จะใช้โอเปอเรเตอร์สำหรับข้อมูลที่ (การพูดเชิงคณิตศาสตร์) ที่ถูกต้อง
Michael K

@Michael คุณไม่สามารถอยู่กับlist.get(n)ไวยากรณ์ได้หรือไม่

@ Thorbjørn: จริง ๆ แล้วก็ดีเช่นกันอาจเป็นตัวอย่างที่ไม่ดี เวลาอาจจะดีกว่า - การโหลดมากเกินไป +, - จะสมเหตุสมผลมากกว่าเวลาเพิ่ม (เวลาอื่น)
Michael K

4
@Michael: เกี่ยวกับรายการที่เชื่อมโยงstd::listไม่เกินoperator[](หรือให้วิธีการอื่น ๆ ของการทำดัชนีในรายการ) เนื่องจากการดำเนินการดังกล่าวจะเป็น O (n) และรายการอินเทอร์เฟซไม่ควรเปิดเผยฟังก์ชั่นดังกล่าวหากคุณสนใจเรื่องประสิทธิภาพ ลูกค้าอาจถูกล่อลวงให้ทำซ้ำมากกว่ารายการที่เชื่อมโยงกับดัชนีทำให้ O (n) อัลกอริทึมไม่จำเป็น O (n ^ 2) คุณเห็นว่าค่อนข้างบ่อยในรหัส Java โดยเฉพาะถ้าคนทำงานกับListส่วนต่อประสานที่มีวัตถุประสงค์เพื่อความซับซ้อนเป็นนามธรรมออกไปอย่างสมบูรณ์
fredoverflow

5
@Thor: "แต่ในการสั่งซื้อเพื่อให้แน่ใจคุณต้องตรวจสอบ :)" ... อีกครั้งนี้จะไม่เชื่อมโยงไปยังผู้ประกอบการบรรทุกเกินพิกัด หากคุณเห็นtime.add(anotherTime)คุณจะต้องตรวจสอบว่าโปรแกรมเมอร์ไลบรารี่ดำเนินการเพิ่ม "ถูกต้อง" หรือไม่
fredoverflow

3

ความแตกต่างอย่างหนึ่งระหว่างการบรรทุกเกินพิกัดa * bและการโทรmultiply(a,b)ก็คือการที่โลภหลังสามารถทำได้ง่าย หากmultiplyฟังก์ชั่นมากเกินไปไม่ได้สำหรับประเภทแล้วคุณจะพบว่าสิ่งที่ทำงานจะไปทำโดยไม่ต้องมีการติดตามผ่านประเภทของและab

Linus Torvalds มีข้อโต้แย้งที่น่าสนใจเกี่ยวกับการบรรทุกเกินพิกัด ในบางอย่างเช่นการพัฒนาเคอร์เนลของ linux ซึ่งการเปลี่ยนแปลงส่วนใหญ่จะถูกส่งผ่านแพตช์ผ่านอีเมลสิ่งสำคัญคือผู้ดูแลระบบสามารถเข้าใจได้ว่าแพตช์จะทำอย่างไรกับบริบทเพียงไม่กี่บรรทัดในแต่ละรอบการเปลี่ยนแปลง หากฟังก์ชั่นและตัวดำเนินการไม่ได้โหลดมากเกินไปแพตช์สามารถอ่านได้ง่ายขึ้นในบริบทที่เป็นอิสระเนื่องจากคุณไม่จำเป็นต้องผ่านไฟล์ที่มีการเปลี่ยนแปลงโดยดูจากประเภททั้งหมดและตรวจสอบตัวดำเนินการที่โอเวอร์โหลด


เคอร์เนล linux ไม่พัฒนาใน pure C หรือไม่? ทำไมถึงพูดคุย (โอเปอเรเตอร์) การบรรทุกเกินพิกัดในบริบทนี้
fredoverflow

ข้อกังวลนั้นเหมือนกันสำหรับโครงการใด ๆ ที่มีกระบวนการพัฒนาที่คล้ายกันโดยไม่คำนึงถึงภาษา การบรรทุกเกินพิกัดมากเกินไปอาจทำให้ยากต่อการเข้าใจถึงผลกระทบของการเปลี่ยนแปลงหากสิ่งที่คุณต้องทำต่อไปนั้นเป็นเพียงไม่กี่บรรทัดจากไฟล์ปะแก้
สกอตต์เวลส์

@FredOverflow: เคอร์เนล Linux อยู่ใน GCC C จริงๆ มันใช้ส่วนขยายทุกประเภทที่ให้ C รู้สึกเกือบ C ++ ในบางครั้ง ฉันกำลังคิดถึงการดัดแปลงประเภทแฟนซีบางอย่าง
Zan Lynx

2
@Scott: ไม่มีประเด็นใดที่จะพูดถึง "ความชั่วร้าย" ของการโอเวอร์โหลดที่เกี่ยวกับโครงการที่ตั้งโปรแกรมใน C เนื่องจาก C ไม่มีความสามารถในการโอเวอร์โหลดฟังก์ชั่น
fredoverflow

3
Linus Torvalds ดูเหมือนว่าฉันจะมีมุมมองที่แคบ บางครั้งเขาวิพากษ์วิจารณ์สิ่งต่าง ๆ ที่ไม่เป็นประโยชน์สำหรับการเขียนโปรแกรมเคอร์เนลลินุกซ์ราวกับว่ามันไม่เหมาะสมสำหรับการใช้งานทั่วไป การโค่นล้มเป็นตัวอย่างหนึ่ง มันเป็น VCS ที่ดี แต่การพัฒนาเคอร์เนลของ Linux ต้องการ VCS แบบกระจายจริงๆดังนั้น Linus จึงวิจารณ์ SVN โดยทั่วไป
David Thornley

2

ฉันสงสัยว่ามีบางอย่างเกี่ยวข้องกับการทำลายความคาดหวัง ฉันคุ้นเคยกับ C ++ คุณคุ้นเคยกับพฤติกรรมของผู้ปฏิบัติงานที่ไม่ได้ถูกกำหนดด้วยภาษาอย่างสมบูรณ์และคุณจะไม่แปลกใจเมื่อผู้ดำเนินการทำสิ่งที่แปลก หากคุณคุ้นเคยกับภาษาที่ไม่มีคุณสมบัตินั้นแล้วดูรหัส C ++ คุณจะนำความคาดหวังจากภาษาอื่น ๆ มาใช้และอาจแปลกใจอย่างน่าประหลาดใจเมื่อคุณพบว่าตัวดำเนินการที่ทำงานหนักเกินไปทำสิ่งที่ขี้ขลาด

ส่วนตัวฉันคิดว่ามีความแตกต่าง เมื่อคุณสามารถเปลี่ยนพฤติกรรมของไวยากรณ์ในตัวของภาษามันจะทึบกว่าเหตุผล ภาษาที่ไม่อนุญาตให้ใช้การเขียนโปรแกรมเมตานั้นมีประสิทธิภาพน้อยกว่า syntactically แต่แนวคิดที่เข้าใจง่ายกว่า


ตัวดำเนินการที่โอเวอร์โหลดไม่ควรทำ "สิ่งที่แปลก" ไม่เป็นไรถ้ามันทำอะไรที่ซับซ้อนแน่นอน แต่จะเกินเฉพาะเมื่อมันมีความหมายเดียวที่ชัดเจน
Sjoerd

2

ฉันคิดว่าการใช้งานตัวดำเนินการทางคณิตศาสตร์มากเกินไปไม่ใช่ปัญหาจริงของตัวดำเนินการมากไปใน C ++ ฉันคิดว่าผู้ประกอบการที่บรรทุกเกินพิกัดที่ไม่ควรพึ่งพาบริบทของการแสดงออก (ประเภทประเภท) คือ "ความชั่วร้าย" เช่นการบรรทุกเกินพิกัดหรือแม้กระทั่งเอก, [ ] ( ) -> ->* new delete *คุณมีชุดความคาดหวังบางอย่างจากผู้ให้บริการที่ไม่ควรเปลี่ยนแปลง


+1 อย่าทำให้ [] เท่ากับ ++
Michael K

3
คุณกำลังบอกว่าเราไม่ควรจะเกินตัวดำเนินการที่คุณพูดถึงเลยเหรอ? หรือคุณเพียงแค่บอกว่าเราควรให้มากไปเพื่อจุดประสงค์ที่มีเหตุผลเท่านั้น? เพราะฉันเกลียดที่จะเห็นภาชนะบรรจุที่ไม่มีoperator[]ผู้ปฏิบัติงานที่ไม่มีoperator()ตัวชี้สมาร์ทที่ไม่มีoperator->และอื่น ๆ
fredoverflow

ฉันกำลังบอกว่าปัญหาที่เป็นไปได้ของการใช้งานตัวดำเนินการมากเกินไปกับการดำเนินการทางคณิตศาสตร์นั้นเล็กเมื่อเทียบกับตัวดำเนินการ การทำสิ่งที่ฉลาดหรือบ้าคลั่งกับตัวดำเนินการทางคณิตศาสตร์อาจทำให้เกิดปัญหา แต่ตัวดำเนินการที่ฉันระบุไว้ซึ่งผู้คนมักจะไม่คิดว่าเป็นตัวดำเนินการ แต่เป็นองค์ประกอบทางภาษาขั้นพื้นฐานควรเป็นไปตามความคาดหวังที่กำหนดโดยภาษา []ควรเป็น accessor เหมือน array และ->ควรหมายถึงการเข้าถึงสมาชิกเสมอ ไม่สำคัญว่าจะเป็นอาร์เรย์หรือคอนเทนเนอร์อื่นจริง ๆ หรือว่าเป็นตัวชี้อัจฉริยะหรือไม่
Allon Guralnek

2

ฉันเข้าใจดีว่าคุณไม่ชอบข้อโต้แย้งของ Joel เกี่ยวกับการซ่อนตัว ฉันก็ไม่เหมือนกัน. มันดีกว่าการใช้ '+' สำหรับสิ่งต่าง ๆ เช่นประเภทตัวเลขในตัวหรือสำหรับคนของคุณเองเช่นพูดเมทริกซ์ ฉันยอมรับว่านี่เป็นระเบียบและสง่างามที่สามารถคูณเมทริกซ์สองตัวด้วย '*' แทน '.multiply ()' และหลังจากทั้งหมดเราก็มีสิ่งที่เป็นนามธรรมในทั้งสองกรณี

สิ่งที่เจ็บที่นี่คือการอ่านรหัสของคุณ ในกรณีของชีวิตจริงไม่ใช่ในตัวอย่างทางวิชาการของการคูณเมทริกซ์ =:=โดยเฉพาะอย่างยิ่งถ้าภาษาของคุณจะช่วยให้การกำหนดผู้ประกอบการที่ไม่ได้อยู่ในขั้นต้นอยู่ในหลักภาษาเช่น ในตอนนี้มีคำถามพิเศษมากมายเกิดขึ้น สิ่งที่ผู้ประกอบการแช่งเกี่ยวกับอะไร ฉันหมายถึงความสำคัญของสิ่งนั้นคืออะไร? การเชื่อมโยงคืออะไร? ลำดับใดที่a =:= b =:= cถูกดำเนินการจริง ๆ

นี่เป็นข้อโต้แย้งกับผู้ปฏิบัติงานมากไป ยังไม่มั่นใจใช่ไหม การตรวจสอบกฎที่สำคัญกว่านั้นทำให้คุณไม่เกิน 10 วินาทีหรือไม่ ตกลงกันเถอะ

หากคุณเริ่มใช้ภาษาที่อนุญาตให้ผู้ปฏิบัติงานโอเวอร์โหลดตัวอย่างเช่นภาษายอดนิยมที่ชื่อขึ้นต้นด้วย 'S' คุณจะได้เรียนรู้อย่างรวดเร็วว่านักออกแบบห้องสมุดชอบที่จะแทนที่ผู้ให้บริการ แน่นอนว่าพวกเขามีการศึกษาดีพวกเขาปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุด (ไม่มีความเห็นถากถางดูถูกที่นี่) และ API ทั้งหมดของพวกเขาทำให้รู้สึกที่สมบูรณ์แบบเมื่อเราดูพวกเขาแยกกัน

ทีนี้ลองนึกว่าคุณจะต้องใช้ API สองสามตัวที่ใช้งานโอเปอเรเตอร์จำนวนมากรวมกันในโค้ดเดียว หรือดียิ่งขึ้น - คุณต้องอ่านรหัสดั้งเดิมเช่นนั้น นี่คือเมื่อผู้ปฏิบัติงานเกินพิกัดจริง ๆ sucks โดยทั่วไปหากมีตัวดำเนินการโอเวอร์โหลดจำนวนมากในที่เดียวพวกเขาจะเริ่มปะปนกับอักขระที่ไม่ใช่ตัวเลขและตัวอักษรอื่น ๆ ในรหัสโปรแกรมของคุณ พวกเขาจะคลาคล่ำไปด้วยอักขระที่ไม่ใช่ตัวเลขที่ไม่ใช่ตัวดำเนินการจริง ๆ แต่มีองค์ประกอบของไวยากรณ์ภาษาพื้นฐานที่กำหนดสิ่งต่างๆเช่นบล็อกและขอบเขตข้อความควบคุมการไหลของรูปร่างหรือแสดงเมตาดาต้าบางตัว คุณจะต้องใส่แว่นตาและขยับตาของคุณเข้าไปใกล้จอ LCD 10 ซม. เพื่อทำความเข้าใจกับความยุ่งเหยิงของภาพ


1
การบรรทุกผู้ประกอบการที่มีอยู่มากเกินไปและการประดิษฐ์ผู้ให้บริการใหม่ไม่ใช่สิ่งเดียวกัน แต่ +1 จากฉัน
fredoverflow

1

โดยทั่วไปแล้วฉันหลีกเลี่ยงการใช้ตัวดำเนินการมากเกินไปในวิธีที่ไม่ง่าย นั่นคือถ้าฉันมีคลาสตัวเลขการโอเวอร์โหลด * เป็นที่ยอมรับได้ (และเป็นกำลังใจ) อย่างไรก็ตามถ้าฉันมีพนักงานชั้นเรียนการทำงานหนักเกินพิกัด * จะทำอย่างไร กล่าวอีกนัยหนึ่งคือการใช้งานโอเวอร์โหลดในรูปแบบที่ใช้งานง่ายซึ่งทำให้อ่านและเข้าใจได้ง่าย

ได้รับการยอมรับ / การสนับสนุน:

class Complex
{
public:
    double r;
    double i;

    Complex operator*(const Compex& rhs)
    {
        Complex result;
        result.r = (r * rhs.r) - (i * rhs.i);
        result.i = (r * rhs.i) + (i * rhs.r);
        return result;
    }
};

ไม่ยอมรับ:

class Employee
{
public:
    std::string name;
    std::string address;
    std::string phone_number;

    Employee operator* (const Employee& e)
    {
        // what the hell do I do here??
    }
};

1
การทวีคูณของพนักงาน? แน่นอนว่ามันเป็นความผิดที่สามารถถูกไล่ออกได้ถ้าพวกเขาทำบนโต๊ะในห้องประชุมนั่นก็คือ
gbjbaanb

1

นอกเหนือจากที่กล่าวไว้ในที่นี้แล้วยังมีข้อโต้แย้งอีกข้อหนึ่งเกี่ยวกับการใช้งานเกินกำลัง แน่นอนถ้าคุณเขียน+สิ่งนี้จะชัดเจนว่าคุณหมายถึงการเพิ่มบางสิ่งลงในบางสิ่ง แต่นี่ไม่ใช่กรณีเสมอไป

C ++ เป็นตัวอย่างที่ดีของกรณีดังกล่าว วิธีการคือstream << 1ควรจะอ่าน? สตรีมเลื่อนไปทางซ้าย 1 ไม่ชัดเจนเลยเว้นแต่คุณจะรู้อย่างชัดเจนว่า << ใน C ++ นั้นเขียนไปยังสตรีมด้วย แต่ถ้าการดำเนินการนี้ถูกนำมาใช้เป็นวิธีการที่ไม่มีนักพัฒนาสติจะเขียนมันจะเป็นสิ่งที่ชอบo.leftShift(1)o.write(1)

บรรทัดล่างคือการทำให้ผู้ปฏิบัติงานไม่สามารถใช้งานได้มากเกินไปภาษาทำให้โปรแกรมเมอร์คิดเกี่ยวกับชื่อของการดำเนินการ แม้ว่าชื่อที่เลือกนั้นไม่สมบูรณ์แบบ แต่ก็ยังยากที่จะตีความชื่อผิด ๆ ว่าเป็นสัญญาณ


1

เมื่อเปรียบเทียบกับวิธีการสะกดคำตัวดำเนินการจะสั้นกว่า แต่ก็ไม่จำเป็นต้องใช้วงเล็บ เครื่องหมายวงเล็บค่อนข้างไม่สะดวกในการพิมพ์ และคุณจะต้องสมดุลพวกเขา โดยรวมแล้วการเรียกใช้เมธอดใด ๆ ต้องการเสียงรบกวนสามตัวเทียบกับตัวดำเนินการ สิ่งนี้ทำให้การใช้โอเปอเรเตอร์น่าดึงดูดมาก
ทำไมอื่นทุกคนต้องการจะนี้cout << "Hello world"?

ปัญหาเกี่ยวกับการโอเวอร์โหลดคือโปรแกรมเมอร์ส่วนใหญ่ขี้เกียจอย่างไม่น่าเชื่อและโปรแกรมเมอร์ส่วนใหญ่ไม่สามารถที่จะเป็นได้

สิ่งที่ผลักดันให้โปรแกรมเมอร์ซีพลัสพลัสไปสู่การใช้งานที่ไม่เหมาะสมของผู้ใช้งานมากเกินไปคือการไม่มีตัวตนของตน และผู้คนไม่เพียง แต่กลัวผู้ปฏิบัติงานมากไปเพราะมันเป็นไปได้ แต่เพราะมันเสร็จแล้ว
โปรดทราบว่าตัวอย่างเช่นใน Ruby และ Scala ไม่มีใครกลัวผู้ประกอบการมากไป นอกเหนือจากความจริงแล้วการใช้ตัวดำเนินการไม่ได้สั้นกว่าวิธีจริง ๆ อีกเหตุผลหนึ่งคือ Ruby จำกัด ตัวดำเนินการมากเกินไปจนเหลือน้อยที่สุดในขณะที่ Scala อนุญาตให้คุณประกาศตัวดำเนินการของคุณเองทำให้หลีกเลี่ยงการชนกันเล็กน้อย


หรือใน C # สำหรับการใช้ + = เพื่อผูกเหตุการณ์กับผู้รับมอบสิทธิ์ ฉันไม่คิดว่าการตำหนิคุณสมบัติภาษาสำหรับความโง่เขลาของโปรแกรมเมอร์เป็นวิธีที่สร้างสรรค์
gbjbaanb

0

เหตุผลที่ Operator Overloading นั้นน่ากลัวเป็นเพราะมีโปรแกรมเมอร์จำนวนมากที่ไม่เคยแม้แต่จะคิด*ว่าไม่ได้แปลว่า "ทวีคูณ" ในขณะที่วิธีการfoo.multiply(bar)อย่างน้อยก็ชี้ไปที่โปรแกรมเมอร์คนที่เขียนวิธีการคูณแบบกำหนดเอง . ณ จุดนี้พวกเขาจะสงสัยว่าทำไมและไปตรวจสอบ

ฉันได้ทำงานกับ "โปรแกรมเมอร์ที่ดี" ซึ่งอยู่ในตำแหน่งระดับสูงที่จะสร้างวิธีการที่เรียกว่า "CompareValues" ที่จะใช้เวลา 2 ข้อโต้แย้งและใช้ค่าจากที่หนึ่งไปยังอีกและกลับบูลีน หรือวิธีการที่เรียกว่า "LoadTheValues" ที่จะไปยังฐานข้อมูลสำหรับวัตถุอื่น 3 ตัวรับค่าทำการคำนวณแก้ไขthisและบันทึกลงในฐานข้อมูล

หากฉันทำงานกับทีมที่มีโปรแกรมเมอร์ประเภทนั้นฉันรู้ได้ทันทีว่าตรวจสอบสิ่งที่พวกเขาได้ทำไปแล้ว หากพวกเขาใช้งานโอเปอเรเตอร์มากเกินไปฉันก็ไม่มีทางรู้เลยว่าพวกเขาทำมันยกเว้นว่าพวกเขาทำและไปดู

ในโลกที่สมบูรณ์แบบหรือทีมที่มีโปรแกรมเมอร์ที่สมบูรณ์แบบการใช้งานเกินกำลังเป็นเครื่องมือที่ยอดเยี่ยม ฉันยังไม่ได้ทำงานกับทีมโปรแกรมเมอร์ที่สมบูรณ์แบบ แต่นั่นเป็นเหตุผลว่าทำไมมันถึงน่ากลัว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.