ทำไมคอมไพเลอร์ Scala ไม่สามารถให้คำเตือนการจับคู่รูปแบบสำหรับคลาส / คุณลักษณะที่ไม่ได้ปิดผนึกได้


10

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

เช่นถ้าฉันมีOption[A]และฉันจับคู่รูปแบบเฉพาะสำหรับSome[A]แต่ไม่ได้สำหรับNoneคอมไพเลอร์จะบ่นเพราะOptionถูกปิดผนึก

หากคอมไพเลอร์ไม่สามารถรู้ / แก้ปัญหานั้นทำไมเขาถึงทำไม่ได้? และถ้าคอมไพเลอร์ (ตามหลักวิชา) สามารถทำเช่นนั้นได้เหตุผลอะไรที่มันไม่ได้ใช้ใน Scala? มีภาษาอื่นที่สนับสนุนพฤติกรรมแบบนั้นหรือไม่?


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

2
หากใครก็ตามสามารถแนะนำคลาสย่อยใหม่การจับคู่รูปแบบจะไม่มีวันหมดสิ้น เช่นคุณผลิตระดับนามธรรมบางอย่างFooกับ subclasses A, BและCและทั้งหมดของการแข่งขันรูปแบบของคุณตรงกับเฉพาะผู้ที่สาม ไม่มีอะไรทำให้ฉันไม่สามารถเพิ่มคลาสย่อยใหม่Dที่จะทำให้รูปแบบของคุณตรงกับความต้องการ
Doval

@kdgregory ใช่คุณเข้าใจแล้ว ฉันเพิ่มตัวอย่างเพื่อให้ชัดเจนยิ่งขึ้น
valenterry

3
การตรวจสอบการนำเข้าทั้งหมดไม่เพียงพอที่จะค้นหาคลาสย่อยที่เป็นไปได้ทั้งหมด subclass อีกอาจจะมีการประกาศในไฟล์แยกชั้นที่เต็มไปต่อมาในช่วง Runtime java.lang.ClassLoaderผ่าน
amon

คำตอบ:


17

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

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

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

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


3

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

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


1
It can be done (at least for all classes known at compile time), it's just expensive.แต่ถ้าโปรแกรมไม่ได้อยู่ในตัวเอง 100% (เช่นมันขึ้นอยู่กับ.jarไฟล์ภายนอก) คุณไม่สามารถแอบในคลาสย่อยใหม่หลังจากทำการคอมไพล์ผ่านหนึ่งในนั้นjarได้หรือไม่? ดังนั้นคอมไพเลอร์สามารถบอกคุณว่า "รูปแบบการจับคู่ของคุณหมดแรงแล้ว แต่อาจเปลี่ยนแปลงได้หากการอ้างอิงใด ๆ ของคุณเปลี่ยนไป"ซึ่งไม่มีค่าเลยเพราะจุดที่มีการพึ่งพาจากภายนอกคือการสามารถอัปเดตได้โดยไม่ต้องคอมไพล์ใหม่!
Doval

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

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

@ArtB ฉันไม่เห็นว่าการมอบหมายหรือการผกผันของการควบคุมจะทำอย่างไรกับสิ่งนี้
Doval

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