บทความล่าสุดที่นำเสนอ compile-time pattern matching แบบใหม่ของ Zig ได้จุดประกายการอภิปรายอย่างร้อนแรงเกี่ยวกับ memory safety ในภาษาโปรแกรมมิ่ง systems programming โพสต์ต้นฉบับได้สาธิตวิธีที่คีย์เวิร์ด inline
และฟีเจอร์ comptime unreachable
ของ Zig สามารถจัดการ partial enum matching ได้อย่างสง่างามโดยไม่มี runtime panics แต่การตอบสนองจากชุมชนได้พัฒนาไปสู่การถกเถียงที่กว้างขึ้นเกี่ยวกับอนาคตของภาษาโปรแกรมมิ่งระดับต่ำ
คุณสมบัติหลักของ Zig ที่กล่าวถึง
- คีย์เวิร์ด
inline
: บังคับให้มีการประเมินผลในเวลาคอมไพล์สำหรับ enum variants หลายตัว comptime unreachable
: การยืนยันในเวลาคอมไพล์ว่าเส้นทางโค้ดนั้นไม่สามารถเข้าถึงได้- การตรวจสอบขอบเขต: การป้องกันอัตโนมัติของ buffer overflows ในโหมดปลอดภัย
defer
/errdefer
: กลไกการทำความสะอาดทรัพยากรอย่างชัดเจน- Metaprogramming ในเวลาคอมไพล์: การสร้างและตรวจสอบโค้ดในเวลาคอมไพล์
ความแบ่งแยกเรื่อง Memory Safety
การอภิปรายนี้เผยให้เห็นความแตกแยกพื้นฐานในชุมชนโปรแกรมเมอร์ระหว่างกลุ่มที่ให้ความสำคัญกับการรับประกันความปลอดภัยในขณะ compile-time และกลุ่มที่ให้ความสำคัญกับความเรียบง่ายและการควบคุมที่ชัดเจน ผู้สนับสนุน Rust โต้แย้งว่า memory safety ควรเป็นสิ่งที่ไม่อาจต่อรองได้ โดยชี้ไปที่ช่องโหว่ด้านความปลอดภัยที่เกิดขึ้นมานานหลายทศวรรษซึ่งเกิดจากบั๊กที่เกี่ยวข้องกับหน่วยความจำ พวกเขามอง manual memory management ของ Zig เป็นการถอยหลังจากความก้าวหน้าที่ได้มาอย่างยากลำบากในการออกแบบภาษา
อย่างไรก็ตาม ผู้สนับสนุน Zig โต้กลับว่ามุมมองนี้ทำให้ภูมิทัศน์ด้านความปลอดภัยดูง่ายเกินไป พวกเขาโต้แย้งว่า Zig ให้การปรับปรุงความปลอดภัยที่มีความหมายเมื่อเทียบกับ C และ C++ โดยเฉพาะใน bounds checking ในขณะที่หลีกเลี่ยงต้นทุนความซับซ้อนที่มาพร้อมกับ ownership system ของ Rust การถกเถียงนี้เน้นย้ำถึงวิธีที่ภาษาต่างๆ ทำการแลกเปลี่ยนที่แตกต่างกันระหว่างการรับประกันความปลอดภัย ความซับซ้อนในการพัฒนา และลักษณะด้านประสิทธิภาพ
เกินกว่าการจำแนก Safety แบบไบนารี
ข้อมูลเชิงลึกสำคัญที่เกิดขึ้นจากการอภิปรายคือ memory safety ไม่ใช่เรื่องแบบไบนารีจริงๆ ในขณะที่ Rust ป้องกันทั้งสองประเภทหลักของ memory unsafety (bounds violations และ use-after-free) Zig เน้นไปที่การป้องกัน bounds violations ที่อันตรายกว่าทางสถิติ ในขณะที่ทำให้ use-after-free bugs ตรวจจับได้ง่ายขึ้น แนวทางที่ละเอียดอ่อนนี้ท้าทายเรื่องเล่าทั่วไปที่ว่าภาษาต่างๆ จะปลอดภัยหรือไม่ปลอดภัยโดยไม่มีจุดกึ่งกลาง
การอภิปรายในชุมชนยังเผยให้เห็นว่าแม้แต่ภาษาที่ปลอดภัยอย่าง Java ก็ไม่ได้มีภูมิคุ้มกันต่อปัญหาหน่วยความจำอย่างสมบูรณ์เมื่อมีโค้ดภายนอกเข้ามาเกี่ยวข้อง การสังเกตนี้ชี้ให้เห็นว่าความปลอดภัยในทางปฏิบัติมักจะขึ้นอยู่กับแนวปฏิบัติของระบบนิเวศและเครื่องมือมากกว่าการรับประกันของภาษาเพียงอย่างเดียว
หมายเหตุ: Bounds checking หมายถึงการป้องกันโปรแกรมจากการเข้าถึงหน่วยความจำนอกพื้นที่ที่จัดสรรไว้โดยอัตโนมัติ Use-after-free เกิดขึ้นเมื่อโปรแกรมเข้าถึงหน่วยความจำที่ถูกยกเลิกการจัดสรรไปแล้ว
การเปรียบเทียบความปลอดภัยของหน่วยความจำ
ภาษา | ความปลอดภัยของขอบเขต | การป้องกัน Use-After-Free | ระดับความซับซ้อน |
---|---|---|---|
C/C++ | แบบแมนนวล | แบบแมนนวล | ปานกลาง-สูง |
Zig | อัตโนมัติ* | แบบแมนนวล | ต่ำ-ปานกลาง |
Rust | อัตโนมัติ* | อัตโนมัติ* | สูง |
Java/Go | อัตโนมัติ | อัตโนมัติ (GC) | ปานกลาง |
การแลกเปลี่ยนระหว่างความซับซ้อนและความปลอดภัย
บางทีแง่มุมที่ถกเถียงกันมากที่สุดของการอภิปรายนี้อยู่ที่ว่าความซับซ้อนเพิ่มเติมของภาษาจะสมเหตุสมผลหรือไม่เมื่อพิจารณาจากประโยชน์ด้านความปลอดภัย ผู้ที่ชื่นชอบ Rust โต้แย้งว่าความซับซ้อนของ borrow checker ให้ผลตอบแทนในการป้องกันบั๊กทั้งคลาสที่มีชื่อเสียงว่ายากต่อการดีบั๊ก ผู้วิจารณ์โต้กลับว่าความซับซ้อนนี้อาจกลายเป็นอุปสรรคต่อประสิทธิภาพการทำงาน โดยเฉพาะเมื่อทำงานกับโค้ดที่ต้องการประสิทธิภาพสูงหรือเชื่อมต่อกับไลบรารี C ที่มีอยู่
ปัญหาของทัศนคตินี้คือคอมไพเลอร์กลายเป็นผู้จัดการระดับกลางที่คุณต้องเอาใจ แทนที่จะเป็นผู้ร่วมงาน
ความรู้สึกนี้สะท้อนถึงความแบ่งแยกทางปรัชญาที่กว้างขึ้นเกี่ยวกับบทบาทของการออกแบบภาษาโปรแกรมมิ่ง นักพัฒนาบางคนชอบการควบคุมที่ชัดเจนและยินดีที่จะรับความรับผิดชอบเพิ่มเติมเพื่อความถูกต้อง ในขณะที่คนอื่นๆ ต้องการให้ภาษาป้องกันข้อผิดพลาดโดยอัตโนมัติ แม้จะต้องแลกกับความเสียดทานเป็นครั้งคราวกับระบบประเภท
มองไปข้างหน้า
การอภิปรายชี้ให้เห็นว่าอนาคตของ systems programming อาจไม่บรรจบกันในแนวทางเดียว โปรเจ็กต์ต่างๆ ที่มีความต้องการที่แตกต่างกันในด้านความปลอดภัย ประสิทธิภาพ และความเร็วในการพัฒนา อาจดึงดูดไปสู่ตัวเลือกภาษาที่แตกต่างกันตามธรรมชาติ ข้อมูลเชิงลึกสำคัญคือแต่ละภาษาแสดงถึงจุดที่แตกต่างกันในพื้นที่หลายมิติของความปลอดภัย ความซับซ้อน ประสิทธิภาพ และประสบการณ์ของนักพัฒนา
แทนที่จะประกาศผู้ชนะและผู้แพ้ ชุมชนดูเหมือนจะตระหนักว่าความหลากหลายในแนวทางภาษาอาจมีคุณค่า ดังที่ผู้เข้าร่วมคนหนึ่งกล่าวไว้ การเลือกระหว่างภาษาอย่าง Rust และ Zig ในที่สุดอาจขึ้นอยู่กับความชอบของทีม ข้อจำกัดของโปรเจ็กต์ และประเภทของปัญหาที่กำลังแก้ไข
อ้างอิง: Partially Matching Zig Enums