ข้อเสนอใหม่ที่จะนำฟีเจอร์ contract programming มาสู่ภาษา C ได้จุดประกายการอภิปรายอย่างเข้มข้นในชุมชนโปรแกรมเมอร์ ข้อเสนอนี้ซึ่งได้รับแรงบันดาลใจจากงาน contracts ที่กำลังดำเนินการอยู่ใน C++ มีเป้าหมายเพิ่ม preconditions และ postconditions ให้กับฟังก์ชัน C แต่นักพัฒนาแบ่งฝ่ายกันอย่างชัดเจนว่าการเพิ่มเติมดังกล่าวจะช่วยหรือทำร้ายภาษานี้
Contract Primitives ที่เสนอสำหรับ C:
contract_assert(COND, "message")
- คล้ายกับ assert ที่มีอยู่แต่ทำงานอยู่เสมอ (ไม่มี NDEBUG)contract_assume(COND, "message")
- ใช้ undefined behavior ผ่านunreachable()
เพื่อการปรับปรุงประสิทธิภาพ- Preconditions:
require: (condition)
- ตรวจสอบเมื่อเข้าสู่ฟังก์ชัน - Postconditions: ตรวจสอบเมื่อฟังก์ชันส่งค่ากลับ
ชุมชนแตกแยกเรื่องปรัชญาการพัฒนาภาษา
ข้อเสนอนี้ได้เปิดเผยความแตกแยกพื้นฐานในชุมชน C programming เกี่ยวกับทิศทางอนาคตของภาษา นักพัฒนาบางคนโต้แย้งว่า C ต้องพัฒนาเพื่อให้ยังคงมีความเกี่ยวข้องในยุคที่ภาษาที่ปลอดภัยต่อหน่วยความจำอย่าง Rust กำลังได้รับความนิยม พวกเขาชี้ให้เห็นว่าภาษาอื่นๆ ได้พัฒนาสำเร็จในขณะที่ยังคงรักษาอัตลักษณ์หลักไว้
อย่างไรก็ตาม ส่วนใหญ่ของชุมชนต่อต้านการเปลี่ยนแปลงใหญ่ใน C อย่างแข็งขัน นักพัฒนาเหล่านี้เชื่อว่าจุดแข็งของ C อยู่ที่ความเรียบง่ายและความน่าเชื่อถือ โดยโต้แย้งว่าภาษานี้ควรมุ่งเน้นไปที่การชี้แจง undefined behavior ที่มีอยู่และปรับปรุงเอกสารแทนที่จะเพิ่มฟีเจอร์ใหม่ พวกเขากังวลว่าความซับซ้อนที่เพิ่มขึ้นอาจทำให้ C กลายเป็นภาษาที่ใช้งานยากเหมือน C++ สมัยใหม่
ความกังวลของชุมชน:
- ความปลอดภัย: พฤติกรรมที่ไม่ได้กำหนดไว้เมื่อสัญญาล้มเหลว เทียบกับการจัดการข้อผิดพลาดที่คาดเดาได้
- ความซับซ้อน: ความเสี่ยงที่ C จะกลายเป็นภาษาที่ซับซ้อนเหมือน C++ สมัยใหม่
- การพัฒนา: มี compiler C++ คุณภาพดีเพียง 3 ตัว เทียบกับ compiler C หลายร้อยตัว
- ปรัชญา: วิวัฒนาการของภาษา เทียบกับการรักษาความเรียบง่ายแบบดั้งเดิมของ C
ข้อกังวลทางเทคนิคเกี่ยวกับความปลอดภัยในการนำไปใช้
ระบบ contract ที่เสนอมานั้นพึ่งพา undefined behavior อย่างมากผ่าน macro unreachable()
ใหม่ใน C23 เมื่อสมมติฐานของ contract ล้มเหลว มันจะทริกเกอร์ undefined behavior ซึ่งช่วยให้คอมไพเลอร์ปรับแต่งโค้ดได้ แต่สร้างความเสี่ยงด้านความปลอดภัยที่อาจเกิดขึ้น นักวิจารณ์โต้แย้งว่าแนวทางนี้แทนที่การจัดการข้อผิดพลาดที่คาดเดาได้ด้วยการทำลายโปรแกรมที่คาดเดาไม่ได้
การนำไปใช้ทางเทคนิคยังทำให้เกิดคำถามเกี่ยวกับประโยชน์ในทางปฏิบัติ ไม่เหมือนภาษาอย่าง Ada หรือ Eiffel ที่สามารถพิสูจน์ contracts ในเวลาคอมไพล์ได้ ข้อเสนอของ C ดูเหมือนจะมุ่งเน้นไปที่การตรวจสอบในรันไทม์และคำแนะนำการปรับแต่งมากกว่า นักพัฒนาบางคนตั้งคำถามว่าสิ่งนี้ให้ประโยชน์เพียงพอที่จะชดเชยความซับซ้อนที่เพิ่มขึ้นหรือไม่
คุณสมบัติ C23/อนาคตที่จำเป็น:
- คำสั่ง
defer
พร้อมdefer_return_value
สำหรับเงื่อนไขหลังการดำเนินการ - ตัวดำเนินการ
typeof
สำหรับการคัดลอกต้นแบบฟังก์ชัน - มาโคร
unreachable()
สำหรับการปรับปรุงประสิทธิภาพพฤติกรรมที่ไม่ได้กำหนด - การสนับสนุน function inlining สำหรับการจัดวาง contract
การถกเถียงระหว่าง Panic กับการจัดการข้อผิดพลาด
จุดขัดแย้งหลักอยู่ที่ปรัชญาการจัดการข้อผิดพลาด ระบบ contract แนะนำพฤติกรรมคล้าย panic เข้ามาใน C ซึ่งการละเมิด contract จะทำให้โปรแกรมหยุดทำงานทันทีแทนที่จะส่งคืนรหัสข้อผิดพลาด นักวิจารณ์โต้แย้งว่าสิ่งนี้เอาการควบคุมออกจากนักพัฒนาที่อาจต้องการจัดการข้อผิดพลาดอย่างสง่างาม
คุณได้แนะนำ panic เข้ามาใน C แล้ว และ panics นั้นแย่ Panics เป็นเหมือนกับดักระเบิดที่รอสถานการณ์โชคร้ายบางอย่างเพื่อทำให้แอปของคุณขัดข้องอย่างไม่คาดคิด ซึ่งคุณไม่สามารถควบคุมได้เพราะการควบคุมการจัดการข้อผิดพลาดถูกแย่งไปจากคุณแล้ว
ผู้สนับสนุนโต้แย้งว่าการขัดข้องใกล้แหล่งที่มาของข้อผิดพลาดพร้อมข้อความที่ชัดเจนนั้นดีกว่าการขัดข้องจาก undefined behavior ที่ลึกลับซึ่งเกิดขึ้นช้ากว่ามากในการดำเนินการ
โซลูชันทางเลือกและเครื่องมือที่มีอยู่
สมาชิกชุมชนหลายคนได้ชี้ไปที่โซลูชันที่มีอยู่ซึ่งตอบสนองความต้องการที่คล้ายกันโดยไม่ต้องเปลี่ยนแปลงภาษา บางคนแนะนำว่า hygenic macros ที่เพิ่มเข้าไปใน header assert.h ที่มีอยู่สามารถให้ฟังก์ชันการทำงานส่วนใหญ่ที่ต้องการได้ คนอื่นๆ อ้างอิงเครื่องมืออย่างฟีเจอร์ bounds-safety ของ Clang หรือภาษาอย่าง Ada/SPARK ที่มีระบบ contract ที่เป็นผู้ใหญ่แล้ว
การอภิปรายยังเน้นให้เห็นว่า Digital Mars C++ ได้รวม contracts ไว้ตั้งแต่ต้นทศวรรษ 1990 ทำให้เกิดคำถามว่าทำไมฟีเจอร์ดังกล่าวจึงไม่ได้รับการยอมรับอย่างกว้างขวางในระบบนิเวศ C/C++ แม้จะมีมาหลายทศวรรษแล้ว
การถกเถียงสะท้อนความตึงเครียดที่กว้างขึ้นในการเขียนโปรแกรมระบบระหว่างการรักษาความเรียบง่ายแบบดั้งเดิมของ C และการปรับตัวให้เข้ากับข้อกำหนดความปลอดภัยสมัยใหม่ เมื่อความปลอดภัยของหน่วยความจำกลายเป็นสิ่งสำคัญมากขึ้นสำหรับความปลอดภัย ชุมชน C เผชิญกับการตัดสินใจที่ยากลำบากเกี่ยวกับว่าภาษานี้สามารถรับการเปลี่ยนแปลงได้มากแค่ไหนในขณะที่ยังคงซื่อสัตย์ต่อปรัชญาการออกแบบเดิม
อ้างอิง: Contracts for C