เหตุใดผู้ประกอบการที่ผู้ใช้กำหนดเองจึงไม่ได้พบเห็นได้บ่อยนัก


94

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

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

ฉันมองไปรอบ ๆ และไม่พบภาษาที่ใช้ในการดำเนินการใด ๆ ที่รองรับตัวดำเนินการที่กำหนดเองในภาษานั้น มีแฮ็ก (เช่นมาโครใน C ++) แต่แทบจะไม่เหมือนกับภาษาที่รองรับ

เนื่องจากคุณสมบัตินี้ค่อนข้างง่ายต่อการนำไปใช้ทำไมจึงไม่เป็นเรื่องปกติ

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

กรณีการใช้งานจริง:

  • ใช้โอเปอเรเตอร์ที่หายไป (เช่น Lua ไม่มีโอเปอเรเตอร์ bitwise)
  • Mimic D's ~(การต่อข้อมูลอาร์เรย์)
  • DSLs
  • ใช้|เป็นไวยากรณ์น้ำตาลแบบ Unix pipe (ใช้ coroutines / generators)

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


4
มีการสนทนา Redditเกิดขึ้นเกี่ยวกับคำถามนี้
แบบไดนามิก

2
@dimatura: ฉันไม่รู้เกี่ยวกับ R มากนัก แต่มันก็เป็นตัวดำเนินการที่กำหนดเองที่ดูเหมือนจะไม่ยืดหยุ่นมาก (เช่นไม่มีวิธีที่เหมาะสมในการกำหนด fixity, ขอบเขต, การบรรทุกเกินพิกัด ฯลฯ ) ซึ่งอธิบายว่าทำไมพวกเขาไม่ได้ใช้มากนัก ที่แตกต่างกันในภาษาอื่น ๆ อย่างแน่นอนใน Haskell ซึ่งใช้ประกอบการมัดกำหนดเองจำนวนมากที่ดี อีกตัวอย่างหนึ่งของภาษาเชิงโพรซีเดอร์ที่มีการสนับสนุน custom-infix ที่เหมาะสมคือNimrodและแน่นอนว่าPerl ยังอนุญาตให้ใช้
leftaroundabout

4
มีตัวเลือกอื่น ๆ เสียงกระเพื่อมจริงไม่มีความแตกต่างระหว่างผู้ประกอบการและฟังก์ชั่น
BeardedO

4
ยังไม่มีการกล่าวถึง Prolog ซึ่งเป็นภาษาอื่นที่ตัวดำเนินการเป็นเพียงน้ำตาล syntactic สำหรับฟังก์ชั่น (ใช่แม้แต่คณิตศาสตร์) และที่ช่วยให้คุณกำหนดผู้ประกอบการที่กำหนดเองด้วยความสำคัญที่กำหนดเอง
David Cowden

2
@ BeardedO ไม่มีผู้ให้บริการมัดใน Lisp เลย เมื่อคุณแนะนำพวกเขาคุณจะต้องจัดการกับปัญหาทั้งหมดที่มีความสำคัญและดังกล่าว
SK-logic

คำตอบ:


134

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

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


23
จากทั้งสองโรงเรียนแห่งความคิดplus.google.com/110981030061712822816/posts/KaSKeg4vQtz +1 ด้วยสำหรับคำตอบที่ตรงที่สุด (และน่าจะเป็นจริงมากที่สุด) สำหรับคำถามที่ว่าทำไมนักออกแบบภาษาจึงเลือกที่หนึ่งกับที่อื่น ฉันจะบอกว่าตามวิทยานิพนธ์ของคุณคุณสามารถคาดการณ์ได้ว่าภาษาที่น้อยลงจะช่วยให้มันได้เพราะส่วนเล็ก ๆ ของนักพัฒนามีทักษะสูงกว่าอย่างอื่น (ร้อยละด้านบนของสิ่งใดจะเป็นชนกลุ่มน้อยตามคำจำกัดความ)
Jimmy Hoffa

12
ฉันคิดว่าคำตอบนี้คลุมเครือและเกี่ยวข้องกับคำถามเพียงเล็กน้อยเท่านั้น (ฉันก็คิดว่าลักษณะของคุณผิดเพราะขัดกับประสบการณ์ของฉัน แต่นั่นไม่สำคัญ)
Konrad Rudolph

1
ดังที่ @ KonradRudolph กล่าวสิ่งนี้ไม่ได้ตอบคำถามจริงๆ ใช้ภาษาอย่าง Prolog ซึ่งช่วยให้คุณทำทุกอย่างที่คุณต้องการด้วยโอเปอเรเตอร์รวมถึงกำหนดความสำคัญของพวกเขาเมื่อวาง infix หรือคำนำหน้า ฉันไม่คิดว่าความจริงที่ว่าคุณสามารถเขียนโอเปอเรเตอร์ที่กำหนดเองนั้นเกี่ยวข้องกับระดับทักษะของกลุ่มเป้าหมาย แต่เพราะเป้าหมายของ Prolog คือการอ่านอย่างมีเหตุผลมากที่สุด การรวมโอเปอเรเตอร์ที่กำหนดเองช่วยให้คุณสามารถเขียนโปรแกรมที่อ่านอย่างมีเหตุผล (หลังจากโปรแกรม prolog ทั้งหมดเป็นเพียงข้อความทางตรรกะจำนวนมาก)
David Cowden

ฉันจะพลาดคำพูดรุนแรงที่สตีวีได้อย่างไร โอ้ผู้ชายคั่นหน้าแล้ว
George Mauer

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

83

ได้รับตัวเลือกระหว่างการต่อข้อมูลอาร์เรย์กับ ~ หรือกับ "myArray.Concat (secondArray)" ฉันอาจจะชอบแบบหลัง ทำไม? เพราะ ~ เป็นอักขระที่ไม่มีความหมายอย่างสมบูรณ์ที่มีเพียงความหมายของมัน - คือการเรียงต่อกันแบบอาเรย์ - ให้ไว้ในโครงการเฉพาะที่มีการเขียน

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

นี่คือเหตุผลที่ฉันไม่ชอบ.โอเปอเรเตอร์ของ PHP (string concatenation) หรือโอเปอเรเตอร์ส่วนใหญ่ใน Haskell หรือ OCaml ถึงแม้ว่าในกรณีนี้มาตรฐานที่ยอมรับกันทั่วไปบางอย่างก็เกิดขึ้นสำหรับภาษาที่ใช้งานได้


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

33
ดังที่ฉันได้กล่าวไว้ในตอนท้ายผู้ปฏิบัติงานบางคนมีความเป็นสากลที่เป็นที่ยอมรับ (เช่นสัญลักษณ์เลขคณิตมาตรฐานการเลื่อนระดับบิตและ / หรืออื่น ๆ ) และดังนั้นความอดทนของพวกเขาจึงมีค่ามากกว่าความทึบ แต่ความสามารถในการกำหนดโอเปอเรเตอร์ตามอำเภอใจดูเหมือนจะทำให้โลกทั้งสองแย่ที่สุด
Avner Shahar-Kashtan

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

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

10
สิ่งที่ต้องใช้เวลานานในการพิจารณาคือการเขียนโค้ดไม่ได้เกี่ยวกับการให้คอมพิวเตอร์ทำอะไรให้คุณ แต่เป็นการสร้างเอกสารที่ทั้งคนและคอมพิวเตอร์สามารถอ่านได้โดยที่คนมีความสำคัญมากกว่าคอมพิวเตอร์ คำตอบนี้ถูกต้องแน่นอนหากบุคคลต่อไป (หรือคุณใน 2 ปี) ต้องใช้เวลาแม้แต่ 10 วินาทีในการหาว่า ~ หมายถึงอะไรคุณอาจใช้เวลา 10 วินาทีในการพิมพ์วิธีการแทน
Bill K

71

เนื่องจากคุณสมบัตินี้ค่อนข้างง่ายต่อการนำไปใช้ทำไมจึงไม่เป็นเรื่องปกติ

หลักฐานของคุณผิด มันไม่ได้ “สวยน่ารำคาญในการดำเนินการ” ในความเป็นจริงมันนำถุงของปัญหา

ลองมาดูคำแนะนำ "การแก้ปัญหา" ในโพสต์:

  • ไม่มีความสำคัญ ผู้เขียนเองกล่าวว่า“ การไม่ใช้กฎที่มีลำดับความสำคัญไม่ใช่เพียงตัวเลือก”
  • ความหมายของการแยกตระหนัก เช่นเดียวกับบทความที่บอกว่าสิ่งนี้จะทำให้คอมไพเลอร์ต้องมีความรู้เชิงความหมายจำนวนมาก บทความไม่ได้เสนอวิธีแก้ปัญหาสำหรับเรื่องนี้และให้ฉันบอกคุณว่านี่ไม่ใช่เรื่องเล็กน้อย คอมไพเลอร์ได้รับการออกแบบเป็นการแลกเปลี่ยนระหว่างพลังและความซับซ้อน โดยเฉพาะอย่างยิ่งผู้เขียนกล่าวถึงขั้นตอนการแยกวิเคราะห์ล่วงหน้าเพื่อรวบรวมข้อมูลที่เกี่ยวข้อง แต่การวิเคราะห์คำล่วงหน้านั้นไม่มีประสิทธิภาพและคอมไพเลอร์พยายามอย่างหนักในการลดการแยกวิเคราะห์
  • ไม่มีผู้ประกอบการมัดกำหนดเอง นั่นไม่ใช่วิธีแก้ปัญหา
  • วิธีการแก้ปัญหาไฮบริด วิธีการแก้ปัญหานี้มีข้อเสียของการแยกวิเคราะห์ทราบความหมายจำนวนมาก (แต่ไม่ทั้งหมด) โดยเฉพาะอย่างยิ่งเนื่องจากคอมไพเลอร์ต้องรักษาโทเค็นที่ไม่รู้จักว่าอาจเป็นตัวแทนของตัวดำเนินการที่กำหนดเองจึงไม่สามารถสร้างข้อความแสดงข้อผิดพลาดที่มีความหมายได้ นอกจากนี้ยังอาจต้องการคำจำกัดความของผู้ดำเนินการดังกล่าวเพื่อดำเนินการแยกวิเคราะห์ (เพื่อรวบรวมข้อมูลประเภท ฯลฯ ) อีกครั้งซึ่งจำเป็นต้องมีการแยกวิเคราะห์เพิ่มเติมอีกครั้ง

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


2
ขอบคุณสำหรับเสียงของสติ ประสบการณ์ของฉันแสดงให้เห็นว่าผู้คนที่เพิกเฉยสิ่งต่าง ๆ เป็นเรื่องไม่สำคัญไม่ว่าจะเป็นผู้เชี่ยวชาญหรือไม่รู้เรื่องอย่างไร้ความปราณีและบ่อยครั้งในหมวดหมู่หลัง: x
Matthieu M.

14
ทุกหนึ่งเดียวของปัญหาเหล่านี้ได้รับการแก้ไขในภาษาที่มีอยู่เป็นเวลา 20 ปี ...
ฟิลิปเจเอฟ

11
และยังเป็นเรื่องเล็กน้อยที่จะนำไปใช้ ลืมเกี่ยวกับอัลกอริทึมการแยกวิเคราะห์หนังสือมังกรนั่นคือศตวรรษที่ 21 และถึงเวลาที่ต้องดำเนินการต่อ แม้แต่การขยายไวยากรณ์ภาษาก็ทำได้ง่ายและการเพิ่มโอเปอเรเตอร์ของลำดับความสำคัญที่กำหนดนั้นไม่สำคัญ ลองดูที่ Haskell parser ดูสิ มันง่ายกว่าตัวแยกวิเคราะห์สำหรับภาษาที่ "สำคัญ" มาก
SK-logic

3
@ SK-logic การยืนยันแบบครอบคลุมของคุณไม่ทำให้ฉันมั่นใจ ใช่การแยกวิเคราะห์ย้ายแล้ว ไม่การใช้โอเปอเรเตอร์สำคัญกว่านั้นขึ้นอยู่กับประเภทนั้นไม่ได้“ ไม่สำคัญ” การสร้างข้อความแสดงข้อผิดพลาดที่ดีโดยมีบริบทที่ จำกัด ไม่ได้“ ไม่สำคัญ” การผลิตตัวแยกวิเคราะห์ที่มีประสิทธิภาพด้วยภาษาที่ต้องใช้หลายรอบในการเปลี่ยนรูปไม่สามารถทำได้
Konrad Rudolph

6
ใน Haskell การแยกวิเคราะห์เป็น "ง่าย" (เทียบกับภาษาส่วนใหญ่) ลำดับความสำคัญเป็นบริบทที่เป็นอิสระ ส่วนที่ให้ข้อความแสดงข้อผิดพลาดที่เกี่ยวกับคุณลักษณะของ typeclass และประเภทของระบบขั้นสูงไม่ใช่ตัวดำเนินการที่ผู้ใช้กำหนด มันเป็นภาระมากเกินไปไม่ใช่คำจำกัดความของผู้ใช้ซึ่งเป็นปัญหาที่ยาก
Philip JF

25

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

โอเปอเรเตอร์ Infix มีปัญหามากกว่ากฎที่มีความสำคัญมาก่อน (แม้ว่าจะเป็นทู่ลิงค์ที่คุณอ้างอิงถึงผลกระทบเล็กน้อยจากการตัดสินใจออกแบบนั้น) หนึ่งคือการแก้ไขความขัดแย้ง: เกิดอะไรขึ้นเมื่อคุณกำหนดa.operator+(b)และb.operator+(a)? ต้องการหนึ่งอย่างเหนือสิ่งอื่นใดเพื่อนำไปสู่การทำลายทรัพย์สินที่คาดหวังของผู้ประกอบการนั้น การโยนข้อผิดพลาดสามารถนำไปสู่โมดูลที่มิฉะนั้นจะทำงานผิดพลาดเมื่อรวมกัน จะเกิดอะไรขึ้นเมื่อคุณเริ่มโยนประเภทที่ได้มาลงในส่วนผสม

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

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

และตรงไปตรงมาเพราะพวกเขาไม่ได้ทำอะไรเล็กน้อย


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

1
@tjameson - ใช่ภาษาจะมีกฎระเบียบที่ชัดเจนสำหรับความสำคัญสำหรับคณิตศาสตร์ boost::spiritกฎระเบียบมีความสำคัญสำหรับการดำเนินการทางคณิตศาสตร์จะไม่ได้จริงๆใช้หากผู้ประกอบการที่ถูกมากเกินไปสำหรับสิ่งที่ต้องการ ทันทีที่คุณอนุญาตให้ผู้ใช้กำหนดโอเปอเรเตอร์ที่แย่ลงเนื่องจากไม่มีวิธีที่ดีในการกำหนดลำดับความสำคัญสำหรับคณิตศาสตร์ ฉันได้เขียนเล็ก ๆ น้อย ๆเกี่ยวกับตัวเองในบริบทของภาษาที่มีลักษณะเฉพาะเพื่อแก้ไขปัญหากับผู้ประกอบการกำหนดโดยพลการ
Telastyn

22
ฉันเรียกพล่ามครับ มีชีวิตนอก OO-ghetto และฟังก์ชั่นไม่จำเป็นต้องเป็นของวัตถุใด ๆดังนั้นการค้นหาฟังก์ชั่นที่ถูกต้องจะเหมือนกับการค้นหาผู้ปฏิบัติงานที่ถูกต้อง
Matthieu M.

1
@matthieuM - แน่นอน กฎความเป็นเจ้าของและการจัดส่งมีความเหมือนกันในภาษาเหล่านั้นที่ไม่สนับสนุนฟังก์ชั่นสมาชิก ณ จุดแม้ว่าคำถามเดิมจะกลายเป็น 'ทำไมไม่ภาษาที่ไม่ใช่ OO ทั่วไปมากขึ้น?' ซึ่งเป็น ballgame อื่นทั้งหมด
Telastyn

11
คุณได้ดูว่าผู้ให้บริการกำหนดเองทำอย่างไรกับ Haskell พวกเขาทำงานตรงเช่นหน้าที่ตามปกติยกเว้นพวกเขายังมีความสำคัญที่เกี่ยวข้อง (อันที่จริงแล้วฟังก์ชั่นปกติสามารถทำได้ถึงแม้ว่าจะไม่ได้มีความแตกต่างกันจริงๆ) โดยพื้นฐานแล้วโอเปอเรเตอร์จะถูกมัดโดยค่าเริ่มต้นและชื่อเป็นคำนำหน้า แต่นั่นก็คือความแตกต่างเท่านั้น
Tikhon Jelvis

19

ฉันคิดว่าคุณจะประหลาดใจที่มีการใช้งานตัวดำเนินการมากเกินไปในบางรูปแบบ แต่ไม่ได้ใช้กันทั่วไปในชุมชนจำนวนมาก

ทำไมต้องใช้ ~ เพื่อเชื่อมต่อกับอาร์เรย์? ทำไมไม่ใช้ << เช่น Ruby ไม่ ? เนื่องจากโปรแกรมเมอร์ที่คุณทำงานด้วยอาจไม่ใช่โปรแกรมเมอร์ Ruby หรือโปรแกรมเมอร์ D ดังนั้นพวกเขาจะทำอย่างไรเมื่อพวกเขาเจอโค้ดของคุณ? พวกเขาต้องไปและค้นหาความหมายของสัญลักษณ์

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

ยุติธรรมพอคุณคิดว่า? มันเป็นเพียงทีมเล็ก ๆ ส่วนตัวฉันไม่เห็นด้วย นักพัฒนาใหม่ทุกคนถูกกำหนดให้สับสนกับคำศัพท์นี้ เราไม่มีปัญหาเพียงพอในการเรียนรู้โดเมนใหม่หรือไม่?

บนมืออื่น ๆ ที่ฉันมีความสุขที่จะใช้ผู้ประกอบการใน C # เพราะผมคาดหวังว่าคนอื่น ๆ นักพัฒนา C # จะรู้ว่ามันคืออะไร แต่ฉันจะไม่เกินมันเป็นภาษาที่ไม่ได้สนับสนุนโดยการเริ่มต้น??


ฉันไม่เข้าใจตัวอย่าง Double.NaN ของคุณพฤติกรรมนี้เป็นส่วนหนึ่งของข้อมูลจำเพาะของจุดลอยตัวและได้รับการสนับสนุนในทุกภาษาที่ฉันใช้ คุณกำลังบอกว่าตัวดำเนินการที่กำหนดเองไม่ได้รับการสนับสนุนเพราะมันจะสร้างความสับสนให้นักพัฒนาที่ไม่ทราบเกี่ยวกับคุณลักษณะนี้หรือไม่? ฟังดูคล้ายกับการโต้แย้งโดยใช้โอเปอร์เรเตอร์หรือ??ตัวอย่างของคุณ
beatgammit

@tjameson: ถูกต้องจริง ๆ แล้วมันก็มีจุดสัมผัสเล็กน้อยในจุดที่ฉันพยายามจะทำ ฉันคิดถึง ตัวอย่างเช่นฉันเขียนและชอบตัวอย่างนั้น การลบย่อหน้า double.NaN
pdr

6
ฉันคิดว่า "นักพัฒนาใหม่ทุกคนของคุณถูกกำหนดให้สับสนโดยคำศัพท์นี้" จุดนั้นค่อนข้างน่าเบื่อเล็กน้อยกังวลเกี่ยวกับเส้นโค้งการเรียนรู้ของนักพัฒนาใหม่ไปยังฐานรหัสของคุณคือฉันเช่นเดียวกับการกังวลเกี่ยวกับช่วงการเรียนรู้ของนักพัฒนาใหม่ . NET เวอร์ชั่นใหม่ ฉันคิดว่าที่สำคัญกว่านั้นคือเมื่อ devs เรียนรู้มัน (ใหม่. NET หรือฐานรหัสของคุณ) มันสมเหตุสมผลหรือไม่ ถ้าเป็นเช่นนั้นเส้นโค้งการเรียนรู้นั้นมีค่าเพราะผู้พัฒนาแต่ละคนจำเป็นต้องเรียนรู้เพียงครั้งเดียวแม้ว่ารหัสจะต้องใช้เวลานับไม่ถ้วนดังนั้นหากมันปรับปรุงโค้ดให้มีค่าใช้จ่ายน้อย
Jimmy Hoffa

7
@JimmyHoffa เป็นค่าใช้จ่ายที่เกิดขึ้นประจำ ชำระเงินล่วงหน้าสำหรับนักพัฒนาใหม่ทุกคนและส่งผลกระทบต่อนักพัฒนาที่มีอยู่เพราะพวกเขาต้องสนับสนุน มีค่าใช้จ่ายในการจัดทำเอกสารและองค์ประกอบของความเสี่ยง - รู้สึกปลอดภัยพอวันนี้ แต่ 30 ปีที่ผ่านมาทุกคนจะย้ายไปอยู่ภาษาและแอปพลิเคชันตอนนี้เป็น "มรดก" เอกสารเป็นกองนึ่งขนาดใหญ่ และผู้ดูดที่น่าสงสารบางคนจะถูกทิ้งผมของเขาจนขาดความสามารถของโปรแกรมเมอร์ที่ขี้เกียจเกินกว่าจะพิมพ์ ".catcat ()" มูลค่าที่คาดหวังเพียงพอที่จะหักล้างค่าใช้จ่ายหรือไม่
Sylverdrag

3
นอกจากนี้ยังมีข้อโต้แย้งว่า "นักพัฒนาใหม่ทุกคนถูกกำหนดให้สับสนกับคำศัพท์นี้เราไม่มีปัญหาในการเรียนรู้โดเมนใหม่หรือไม่" อาจถูกนำไปใช้กับ OOP ย้อนกลับไปในยุค 80 การเขียนโปรแกรมเชิงโครงสร้างก่อนหน้านั้นหรือ IoC 10 ปีที่ผ่านมา ถึงเวลาที่จะหยุดใช้อาร์กิวเมนต์ที่ผิดพลาดนี้
Mauricio Scheffer

11

ฉันนึกถึงเหตุผลสองสามข้อ:

  • มันไม่สำคัญที่จะนำไปใช้ - การอนุญาตให้ตัวดำเนินการที่กำหนดเองตามอำเภอใจสามารถทำให้คอมไพเลอร์ของคุณซับซ้อนมากขึ้นโดยเฉพาะถ้าคุณอนุญาตให้ผู้ใช้กำหนดกฎมาก่อนความคงที่และกฎ arity หากความเรียบง่ายนั้นเป็นสิ่งที่ดีแล้วผู้ประกอบการที่บรรทุกเกินพิกัดก็จะพาคุณออกไปจากการออกแบบภาษาที่ดี
  • พวกเขาถูกทารุณกรรม - โดยนักเขียนโค้ดที่คิดว่า "เจ๋ง" ในการกำหนดผู้ประกอบการใหม่และเริ่มต้นการกำหนดใหม่สำหรับคลาสแบบกำหนดเองทุกประเภท อีกไม่นานรหัสของคุณจะเต็มไปด้วยสัญลักษณ์ที่กำหนดเองซึ่งไม่มีใครสามารถอ่านหรือเข้าใจได้เพราะผู้ปฏิบัติงานไม่ปฏิบัติตามกฎที่เข้าใจกันทั่วไป ฉันไม่ได้ซื้ออาร์กิวเมนต์ "DSL" เว้นแต่ว่า DSL ของคุณจะเป็นเซตย่อยของคณิตศาสตร์ :-)
  • พวกเขาทำร้ายความสามารถในการอ่านและการบำรุงรักษา - หากผู้ปฏิบัติงานถูกเขียนทับเป็นประจำมันอาจกลายเป็นเรื่องยากที่จะสังเกตเห็นเมื่อมีการใช้สถานที่นี้ มันจะดีกว่ามากถ้าให้ชื่อฟังก์ชันที่มีความหมาย การพิมพ์อักขระพิเศษเล็กน้อยราคาถูกปัญหาการบำรุงรักษาในระยะยาวมีราคาแพง
  • พวกเขาสามารถทำลายความคาดหวังผลการดำเนินงานโดยปริยาย O(1)ยกตัวอย่างเช่นผมปกติคาดหวังการค้นหาขององค์ประกอบในอาร์เรย์จะเป็น แต่ด้วยการบรรทุกเกินพิกัดของผู้ประกอบการsomeobject[i]อาจเป็นเรื่องง่ายO(n)ขึ้นอยู่กับการใช้งานของผู้ประกอบการทำดัชนี

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

กรณีที่น่าสนใจที่ควรพิจารณา:

  • Lisps : โดยทั่วไปจะไม่แยกความแตกต่างระหว่างตัวดำเนินการและฟังก์ชั่น - +เป็นเพียงฟังก์ชั่นปกติ คุณสามารถกำหนดฟังก์ชั่นได้ตามต้องการ (โดยทั่วไปจะมีวิธีกำหนดไว้ในเนมสเปซที่แยกต่างหากเพื่อหลีกเลี่ยงความขัดแย้งกับในตัว+) รวมถึงโอเปอเรเตอร์ แต่มีแนวโน้มทางวัฒนธรรมที่จะใช้ชื่อฟังก์ชั่นที่มีความหมายดังนั้นสิ่งนี้จึงไม่ถูกทารุณกรรมมากนัก นอกจากนี้ในสัญลักษณ์นำหน้าเสียงกระเพื่อมมีแนวโน้มที่จะใช้เฉพาะดังนั้นจึงมีค่าน้อยลงใน "น้ำตาลทราย" ที่ผู้ประกอบการเกินพิกัดให้
  • Java - ไม่อนุญาตให้ผู้ประกอบการโอเวอร์โหลด นี่เป็นครั้งคราวที่น่ารำคาญ (สำหรับสิ่งต่าง ๆ เช่นหมายเลขคอมเพล็กซ์) แต่โดยเฉลี่ยแล้วมันอาจเป็นการตัดสินใจออกแบบที่ถูกต้องสำหรับ Java ซึ่งมีวัตถุประสงค์เพื่อให้ง่ายต่อการใช้งาน OOP อย่างง่าย รหัส Java นั้นค่อนข้างง่ายสำหรับผู้พัฒนาที่มีทักษะต่ำ / ปานกลางที่จะคงไว้ซึ่งเป็นผลมาจากความเรียบง่ายนี้
  • C ++มีการใช้งานตัวดำเนินการมากเกินไปอย่างซับซ้อน บางครั้งสิ่งนี้จะถูกทารุณกรรม ( cout << "Hello World!"ใครก็ตาม) แต่วิธีการนี้ทำให้รู้สึกถึงการวางตำแหน่งของภาษา C ++ ซึ่งเป็นภาษาที่ซับซ้อนที่ช่วยให้การเขียนโปรแกรมระดับสูงในขณะที่ยังช่วยให้คุณได้ใกล้ชิดกับโลหะมากขึ้นในการปฏิบัติงาน ตรงตามที่คุณต้องการโดยไม่ลดทอนประสิทธิภาพ เป็นที่เข้าใจกันว่ามันเป็นความรับผิดชอบของคุณเองถ้าคุณยิงตัวเองด้วยการเดินเท้า

8

เนื่องจากคุณสมบัตินี้ค่อนข้างง่ายต่อการนำไปใช้ทำไมจึงไม่เป็นเรื่องปกติ

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

ที่กล่าวว่าฉันสามารถคิดสามภาษาที่ทำมันและพวกเขาทำในรูปแบบที่แตกต่างกัน:

  • แร็กเก็ตแบบแผนเมื่อมันไม่ใช่ S-expression-y ทั้งหมดจะอนุญาตและคาดว่าคุณจะเขียนจำนวนตัวแยกวิเคราะห์สำหรับไวยากรณ์ใด ๆ ที่คุณต้องการขยาย (และมีตะขอที่เป็นประโยชน์
  • Haskell เป็นภาษาโปรแกรมฟังก์ชั่นล้วนๆช่วยให้สามารถกำหนดโอเปอเรเตอร์ใด ๆ ที่ประกอบด้วยเครื่องหมายวรรคตอนเท่านั้น ตัวดำเนินการ Ternary เป็นต้นสามารถสร้างได้จากตัวดำเนินการไบนารีและฟังก์ชันลำดับที่สูงขึ้น
  • Agda ซึ่งเป็นภาษาการเขียนโปรแกรมที่พึ่งพาได้นั้นมีความยืดหยุ่นอย่างมากกับตัวดำเนินการ (กระดาษที่นี่ ) ทำให้สามารถกำหนดได้ทั้ง if-then และ if-then-else เป็นตัวดำเนินการในโปรแกรมเดียวกัน ผลที่ตามมา.

4
คุณพูดว่า "ไม่สำคัญ" และแสดงรายการสามภาษาทันทีที่มีการใช้งานที่น่ารำคาญอย่างไม่น่าเชื่อ ดังนั้นมันค่อนข้างเล็กน้อยหลังจากทั้งหมดใช่ไหม
SK-logic

7

หนึ่งในสาเหตุหลักที่ผู้ประกอบการกำหนดเองไม่ได้รับการสนับสนุนคือเนื่องจากผู้ประกอบการรายใดสามารถหมายถึง / สามารถทำอะไรก็ได้

ยกตัวอย่างเช่นcstreamวิพากษ์วิจารณ์การเปลี่ยนแปลงซ้ายที่มากเกินไป

เมื่อภาษาอนุญาตให้โอเปอเรเตอร์โอเวอร์โหลดมักจะมีกำลังใจในการทำให้พฤติกรรมของโอเปอเรเตอร์คล้ายกับพฤติกรรมพื้นฐานเพื่อหลีกเลี่ยงความสับสน

ด้วยตัวดำเนินการที่ผู้ใช้กำหนดเองทำให้การแยกวิเคราะห์ยากขึ้นมากโดยเฉพาะเมื่อมีกฎการกำหนดลักษณะเอง


6
ฉันไม่เห็นว่าส่วนต่าง ๆ เกี่ยวกับการใช้งานตัวดำเนินการมากเกินไปเพื่อกำหนดตัวดำเนินการใหม่อย่างสมบูรณ์ได้อย่างไร

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

3
และวิธีนี้แตกต่างจากวิธีการมากไป?
Jörg W Mittag

@ JörgWMittagที่มีเมธอดมากเกินไป (ส่วนใหญ่) จะมีชื่อที่สื่อความหมายแนบมาด้วย ที่มีสัญลักษณ์มันยากที่จะอธิบายชัดถ้อยชัดคำว่าอะไรจะเกิดขึ้น
วงล้อประหลาด

1
@ ratchetfreak: ดี +เพิ่มสองสิ่ง, -ลบออก, *คูณมัน ความรู้สึกของฉันคือไม่มีใครบังคับให้โปรแกรมเมอร์ทำให้ฟังก์ชั่น / วิธีการaddเพิ่มอะไรจริง ๆ และdoNothingอาจเปิดนิวเคลียร์ และa.plus(b.minus(c.times(d)).times(e)สามารถอ่านได้น้อยกว่ามากa + (b - c * d) * e(เพิ่มโบนัส - ซึ่งใน sting แรกคือข้อผิดพลาดในการถอดความ) ผมไม่เห็นว่าเป็นครั้งแรกที่มีความหมายมากขึ้น ...
Maciej Piechotka

4

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

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


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

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

1
มันไม่ใช่ปัญหาของสัญลักษณ์ มันเป็นปัญหาของคีย์บอร์ด ตัวอย่างเช่นฉันใช้ emacs haskell-mode เมื่อเปิดใช้งานยูนิโคด beautifier และมันจะแปลงโอเปอเรเตอร์ ascii ให้เป็นสัญลักษณ์ยูนิโค้ดโดยอัตโนมัติ แต่ฉันจะไม่สามารถพิมพ์ได้หากไม่มี ASCII ที่เทียบเท่า
Vagif Verdi

2
ภาษาธรรมชาติสร้างขึ้นจาก "คำที่ผู้ใช้กำหนด" เท่านั้นและไม่มีอะไรอื่น และบางภาษาสนับสนุนการสร้างคำที่กำหนดเอง
SK-logic

4

สำหรับภาษาที่รองรับการใช้งานมากเกินไป: Scala ทำจริง ๆ แล้วใน C ++ ที่สะอาดกว่าและดีกว่ามาก อักขระส่วนใหญ่สามารถใช้ในชื่อฟังก์ชันได้ดังนั้นคุณสามารถกำหนดโอเปอเรเตอร์เช่น! + * = ++ ได้หากต้องการ มีการสนับสนุนในตัวสำหรับ infix (สำหรับทุกฟังก์ชั่นที่รับหนึ่งอาร์กิวเมนต์) ฉันคิดว่าคุณสามารถกำหนดความสัมพันธ์ของฟังก์ชันดังกล่าวได้เช่นกัน อย่างไรก็ตามคุณไม่สามารถกำหนดลำดับความสำคัญ (เฉพาะกับลูกเล่นขี้เหร่ดูที่นี่ )


4

สิ่งหนึ่งที่ยังไม่ได้กล่าวถึงคือ Smalltalk ซึ่งทุกอย่าง (รวมถึงโอเปอเรเตอร์) คือการส่งข้อความ "ผู้ประกอบการ" ชอบ+, |และอื่น ๆ เป็นวิธีการเอกจริง

วิธีการทั้งหมดสามารถแทนที่ดังนั้นa + bหมายความว่านอกจากจำนวนเต็มถ้าaและbมีทั้งจำนวนเต็มและหมายความว่านอกจากเวกเตอร์ถ้าพวกเขาทั้งสองOrderedCollections

ไม่มีกฎที่มาก่อนเนื่องจากสิ่งเหล่านี้เป็นเพียงการเรียกใช้เมธอด นี้มีความหมายสำคัญสำหรับสัญกรณ์คณิตศาสตร์มาตรฐาน: 3 + 4 * 5วิธีการไม่ได้(3 + 4) * 53 + (4 * 5)

(นี่เป็นบล็อกสำคัญสำหรับมือใหม่ของ Smalltalk การทำลายกฎคณิตศาสตร์ลบกรณีพิเศษเพื่อให้การประเมินโค้ดทั้งหมดดำเนินการเหมือนกันจากซ้ายไปขวาทำให้ภาษานั้นง่ายขึ้นมาก)


3

คุณกำลังต่อสู้กับสองสิ่งที่นี่:

  1. ทำไมโอเปอเรเตอร์มีอยู่ในภาษาตั้งแต่แรก?
  2. คุณธรรมของผู้ปฏิบัติงานเหนือหน้าที่ / วิธีการคืออะไร?

ในภาษาส่วนใหญ่ตัวดำเนินการไม่ได้ถูกนำไปใช้เป็นฟังก์ชั่นที่เรียบง่าย พวกเขาอาจมีฟังก์ชั่นบางส่วนนั่งร้าน แต่คอมไพเลอร์ / รันไทม์ตระหนักถึงความหมายเชิงความหมายของพวกเขาอย่างชัดเจนและวิธีการแปลอย่างมีประสิทธิภาพในรหัสเครื่อง นี่คือความจริงมากยิ่งขึ้นเมื่อเทียบกับฟังก์ชั่นในตัว (ซึ่งเป็นสาเหตุที่การใช้งานส่วนใหญ่ไม่รวมค่าใช้จ่ายการเรียกใช้ฟังก์ชันทั้งหมดในการใช้งาน) ตัวดำเนินการส่วนใหญ่เป็น abstractions ระดับที่สูงขึ้นตามคำแนะนำดั้งเดิมที่พบในซีพียู (ซึ่งส่วนหนึ่งเป็นสาเหตุว่าทำไมตัวดำเนินการส่วนใหญ่เป็นเลขคณิตบูลีนหรือ bitwise) คุณสามารถจำลองพวกมันเป็นฟังก์ชั่น "พิเศษ" (เรียกพวกเขาว่า "primitives" หรือ "builtins" หรือ "native" หรืออะไรก็ตาม) แต่การทำเช่นนั้นโดยทั่วไปต้องมีชุดความหมายที่แข็งแกร่งมากสำหรับการกำหนดฟังก์ชั่นพิเศษดังกล่าว ทางเลือกคือการมีโอเปอเรเตอร์ในตัวที่มีความหมายเหมือนตัวดำเนินการที่ผู้ใช้กำหนด แต่อย่างใดเรียกใช้พา ธ พิเศษในคอมไพเลอร์ นั่นคือคำตอบสำหรับคำถามที่สอง ...

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

ตัวดำเนินการโอเวอร์โหลดของ C ++ ให้พื้นที่ที่สมบูรณ์สำหรับการตรวจสอบสิ่งนี้ โอเปอเรเตอร์โอเวอร์โหลดส่วนใหญ่ "การละเมิด" มาในรูปแบบของโอเวอร์โหลดที่ทำลายสัญญาเชิงความหมายบางอย่างที่เข้าใจอย่างกว้างขวาง (ตัวอย่างคลาสสิกคือโอเวอร์โหลดของโอเปอเรเตอร์ + เช่น a + b! = b + a หรือที่ไหน + แก้ไขอย่างใดอย่างหนึ่ง ถูกดำเนินการ)

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


1

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

บางครั้งมันยากที่จะทำความเข้าใจมากกว่าที่คุณคาดหวัง กาลครั้งหนึ่งในโครงการ C ++ ข้ามแพลตฟอร์มขนาดใหญ่ฉันคิดว่ามันเป็นความคิดที่ดีที่จะทำให้วิธีการที่เส้นทางถูกสร้างขึ้นโดยการสร้างFilePathวัตถุ (คล้ายกับFileวัตถุของ Java ) ซึ่งจะมีตัวดำเนินการ / คุ้นเคยกับการเชื่อมโยงอื่น ส่วนทางนั้น (เพื่อให้คุณสามารถทำสิ่งที่ชอบFile::getHomeDir()/"foo"/"bar"และมันจะทำสิ่งที่ถูกต้องในทุกแพลตฟอร์มที่รองรับของเรา) ทุกคนที่เห็นมันจะพูดว่า "นรกคืออะไร? การแบ่งสาย? ... โอ้น่ารัก แต่ฉันไม่ไว้ใจให้ทำสิ่งที่ถูกต้อง"

ในทำนองเดียวกันมีหลายกรณีในการเขียนโปรแกรมกราฟิกหรือพื้นที่อื่น ๆ ที่คณิตศาสตร์แบบเวกเตอร์ / เมทริกซ์เกิดขึ้นมากมายที่ดึงดูดให้ทำสิ่งต่าง ๆ เช่นเมทริกซ์ * เมทริกซ์เวกเตอร์ * เวกเตอร์ (จุด), เวกเตอร์% เวกเตอร์ (กากบาท), เมทริกซ์เวกเตอร์ * การแปลงเมทริกซ์), เมทริกซ์ ^ เวกเตอร์ (การแปลงเมทริกซ์กรณีพิเศษโดยไม่สนใจพิกัดที่เป็นเนื้อเดียวกัน - มีประโยชน์สำหรับพื้นผิวปกติ) และอื่น ๆ แต่ในขณะที่มันช่วยประหยัดเวลาในการแยกวิเคราะห์สำหรับผู้เขียนห้องสมุดคณิตศาสตร์เวกเตอร์ ทำให้สับสนมากขึ้นสำหรับผู้อื่น มันก็ไม่คุ้มค่า


0

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

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

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

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


"สัญลักษณ์เดียวกันบนหน้าจอจะมีความหมายแตกต่างกันไปตามสิ่งที่อยู่รอบ ๆ " - เป็นกรณีที่ผู้ให้บริการหลายรายในภาษาส่วนใหญ่มีอยู่แล้ว
rkj

-1

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

ผู้ประกอบการมักจะสร้างตรรกะสั้น ๆ ที่กำหนดไว้อย่างดีและจัดทำเป็นเอกสารในภาษาหลัก (เปรียบเทียบกำหนด ... ) พวกเขามักจะเข้าใจยากโดยไม่มีเอกสารประกอบ (เปรียบเทียบa^bกับxor(a,b)ตัวอย่าง) มีตัวดำเนินการจำนวน จำกัด ที่จริง ๆ แล้วอาจสมเหตุสมผลในการเขียนโปรแกรมปกติ (>, <, =, + ฯลฯ .. )

ความคิดของฉันคือการติดชุดของตัวดำเนินการที่กำหนดไว้อย่างดีในภาษา - จากนั้นอนุญาตให้ตัวดำเนินการโอเวอร์โหลดของตัวดำเนินการเหล่านั้น (ให้คำแนะนำอย่างนุ่มนวลว่าตัวดำเนินการควรทำสิ่งเดียวกัน แต่ใช้ชนิดข้อมูลแบบกำหนดเอง)

กรณีการใช้งานของคุณ~และ|จริง ๆ แล้วจะเป็นไปได้ด้วยตัวดำเนินการอย่างง่าย ๆ เกินพิกัด (C #, C ++ ฯลฯ ) DSL เป็นพื้นที่ใช้งานที่ถูกต้อง แต่อาจเป็นหนึ่งในพื้นที่ที่ถูกต้องเท่านั้น (จากมุมมองของฉัน) อย่างไรก็ตามฉันคิดว่ามีเครื่องมือที่ดีกว่าในการสร้างภาษาใหม่ภายใน การใช้ภาษา DSL จริงในภาษาอื่นนั้นไม่ใช่เรื่องยากโดยใช้เครื่องมือคอมไพเลอร์เหล่านั้น กันไปสำหรับ "การขยายอาร์กิวเมนต์ LUA" ภาษาส่วนใหญ่มีแนวโน้มที่จะถูกกำหนดเป็นหลักในการแก้ปัญหาในลักษณะที่เฉพาะเจาะจงไม่ให้เป็นรากฐานสำหรับภาษาย่อย (มีข้อยกเว้นอยู่)


-1

ปัจจัยอีกประการหนึ่งก็คือมันไม่ได้ตรงไปตรงมาเพื่อกำหนดการดำเนินการกับผู้ให้บริการที่มีอยู่ ฉันหมายถึงใช่สำหรับหมายเลขประเภทใดก็ได้ตัวดำเนินการ '*' สามารถเข้าใจได้และมักจะนำไปใช้ในภาษาหรือในโมดูลที่มีอยู่ แต่ในกรณีของคลาสที่ซับซ้อนทั่วไปที่คุณจำเป็นต้องกำหนด (สิ่งต่าง ๆ เช่น ShipingAddress, WindowManager, ObjectDimensions, PlayerCharacter ฯลฯ ) พฤติกรรมนั้นไม่ชัดเจน ... การเพิ่มหรือลบตัวเลขในที่อยู่หมายถึงอะไร ทวีคูณสองที่อยู่?

แน่นอนว่าคุณสามารถกำหนดได้ว่าการเพิ่มสตริงในคลาส ShippingAddress หมายถึงการดำเนินการที่กำหนดเองเช่น "แทนที่บรรทัด 1 ในที่อยู่" (แทนฟังก์ชั่น "setLine1") และการเพิ่มตัวเลขคือ "แทนที่รหัสไปรษณีย์" (แทน "setZipCode") แต่แล้วรหัสไม่สามารถอ่านได้และสับสนมาก โดยทั่วไปเราคิดว่าตัวดำเนินการถูกใช้ในประเภท / คลาสพื้นฐานเนื่องจากพฤติกรรมของพวกเขานั้นใช้งานง่ายชัดเจนและสอดคล้องกัน (เมื่อคุณคุ้นเคยกับภาษาอย่างน้อย) คิดในรูปแบบต่างๆเช่น Integer, String, ComplexNumbers ฯลฯ

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

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