ไม่มีอะไรเป็นประเภทย่อยของทุกประเภทอื่น ๆ ใน Scala


19

ฉันกำลังเรียนหลักสูตร coursera ของ Martin Odersky เกี่ยวกับการเขียนโปรแกรมใช้งานได้กับ scala และตอนนี้ฉันได้เรียนรู้สองสิ่งที่เข้าด้วยกันไม่สมเหตุสมผล:

  1. สกาล่าไม่สนับสนุนการสืบทอดหลายแบบ
  2. Nothing เป็นประเภทย่อยของทุกประเภทอื่น ๆ

ข้อความทั้งสองนี้ไม่สามารถอยู่ด้วยกันได้ดังนั้นสิ่งนี้จะทำอย่างไรกันแน่? และอะไรคือความหมายของ "ประเภทย่อยของทุก ๆ ประเภท"

แก้ไข 1

ในกาลา API , Nothingถูกกำหนดให้เป็นabstract final class Nothing extends Any... ดังนั้นวิธีที่จะสามารถขยายชั้นเรียนอื่น ๆ ?


หน้านี้อาจช่วยเล็กน้อย: artima.com/pins1ed/scalas-hierarchy.html
jhewlett

เท่าที่ผมสามารถเห็นมันถูกกำหนดให้เป็น "ไม่มีอะไรลักษณะสุดท้ายขยายใด ๆ" scala-lang.org/api/2.7.6/scala/Nothing.html
Den

8
คุณกำลังสับสนประเภทและชั้นเรียน ทั้งสองนั้นต่างกันมาก แต่น่าเสียดายที่คุณไม่ได้เป็นเพียงคนเดียวที่เป็นที่สับสนโดยความแตกต่างนั้นและมันน่าเสียดายที่บางส่วนของผู้ที่มีความสับสนเกิดขึ้นจะเป็นนักออกแบบของภาษาที่นิยมเช่น Java, C # และซี ++ ไม่ได้บอกว่าNothingเป็นคลาสย่อยของคลาสอื่น ๆ มันบอกว่ามันเป็นชนิดย่อยของอื่น ๆ ทุกประเภท
Jörg W Mittag

1
@delnan: อินเทอร์เฟซของ Java ถูกนำมาโดยตรงจากโปรโตคอลของ Smalltalk ใน Smalltalk เฉพาะโปรโตคอลเท่านั้นที่เป็นประเภทไม่ใช่คลาส ใน Java ทั้งอินเตอร์เฟสและคลาสเป็นชนิด มันผิด คลาสไม่ใช่ประเภท แต่มีเพียงอินเตอร์เฟสเท่านั้น ความจริงที่ว่าภาษาเหล่านี้ทั้งหมดมีสิ่งที่เป็นประเภทและไม่ใช่คลาสที่ไม่เกี่ยวข้อง ปัญหาคือว่าในชั้นเรียนภาษาเหล่านั้นเป็นประเภทที่ผิด
Jörg W Mittag

1
@ JörgWMittagนั่นเป็นคำสั่งที่แตกต่างกันและมีเหตุผลอย่างมาก (ฉันมักจะเห็นด้วยว่ามันเป็นอันตราย แต่ฉันจะไม่บอกคุณลักษณะนี้กับการพิมพ์ผิด) ไม่มีประเด็นในการพูดคุยที่นี่

คำตอบ:


27

การย่อยและการสืบทอดเป็นสองสิ่งที่แตกต่างกัน! Nothingไม่ขยายทุกอย่างมันเป็นชนิดย่อยAnyก็เพียงขยาย

เปค[§3.5.2]มีกรณีพิเศษว่าด้วยการ subtyping ความสัมพันธ์ของNothing:

§3.5.2ความสอดคล้อง

  • [ ... ]
  • สำหรับประเภทค่าทุก
    T,scala.Nothing <: T <:scala.Any
  • สำหรับตัวสร้างทุกประเภทT(ที่มีพารามิเตอร์ประเภทจำนวนเท่าใดก็ได้)
    scala.Nothing <: T <: scala.Any
  • [ ... ]

อยู่ที่ไหน<:โดยทั่วไปหมายถึง "เป็นชนิดย่อยของ"

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

บ่อยครั้งที่ภาษาทำสิ่งที่คุณเป็นโปรแกรมเมอร์ไม่สามารถทำได้ ในฐานะที่เป็นคู่เพื่อNothing: ทุกอย่างใน Scala สืบทอดจากAnyทุกอย่างยกเว้น Anyทำไมไม่Anyสืบทอดจากบางสิ่ง? คุณทำอย่างนั้นไม่ได้ ทำไมสกาล่าทำเช่นนั้น? ก็เพราะสกาล่าตั้งกฎไม่ใช่คุณ Nothingการเป็นประเภทย่อยของทุกสิ่งเป็นเพียงตัวอย่างอื่นของสิ่งนี้


10
BTW: นี่เป็นสิ่งเดียวกับnullการกำหนดให้กับเขตข้อมูลทุกประเภทใน Java ทำไมเป็นไปได้ เป็นnullตัวอย่างของทุกระดับ? ไม่เป็นไปได้เพราะคอมไพเลอร์พูดอย่างนั้น ระยะเวลา
Jörg W Mittag

8
ถ้าฉันสามารถโหวตได้ร้อยครั้งฉันก็จะทำ ประเภทและคลาสที่สับสนเป็นหนึ่งในสิ่งที่แย่ที่สุดที่ภาษาอย่าง Java ได้นำมาให้เรา
Jörg W Mittag

1
สำหรับวิญญาณที่อยากรู้อยากเห็นเกี่ยวกับความแตกต่างระหว่างการสืบทอดและประเภทย่อยcmi.ac.in/~madhavan/courses/pl2006/lecturenotes/lecture-notes/ …อย่างไรก็ตามฉันไม่ได้ซื้อมัน - ถ้าคุณสืบทอด (เช่นextendsใน Java และไม่ได้เขียน ) คุณทำมันเพื่อพิมพ์ย่อยหลังจากทั้งหมด
greenoldman

11

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

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

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

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

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

For every type constructor T (with any number of type parameters), scala.Nothing <: T <: scala.Any.

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

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


2
สิ่งที่ฉันยังไม่เข้าใจก็คือวิธีนี้จะทำ ... ดูการแก้ไขคำถามของฉัน
vainolo

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