- ภาษาแบบวิวัฒนาการที่สืบทอดไวยากรณ์และความหมายของภาษา C พร้อมเสริมความปลอดภัยและความสะดวกในการใช้งาน โดยยังคงสภาพแวดล้อมที่คุ้นเคยสำหรับนักพัฒนา C เดิม
- รองรับ ความเข้ากันได้กับ C ABI อย่างสมบูรณ์ ทำให้ผสานเข้ากับโปรเจ็กต์ C/C++ ได้ทันที และมีกรณีที่โค้ดบางส่วนของ vkQuake ถูกแปลงเป็น C3 แล้วบิลด์ด้วยคอมไพเลอร์ c3c
- ช่วยยกระดับโครงสร้างและความสามารถในการเขียนโค้ดด้วย ระบบโมดูล, operator overloading, compile-time macro เป็นต้น
- มีความสามารถสมัยใหม่ เช่น การเขียนโปรแกรมแบบอิงสัญญา (Gradual Contracts), การจัดการข้อผิดพลาดแบบไม่มีโอเวอร์เฮด, reflection ทั้งที่รันไทม์และคอมไพล์ไทม์
- ในโหมดดีบักจะมี การตรวจสอบความปลอดภัยและ stack trace แบบละเอียด ให้อัตโนมัติ จึงเหมาะต่อการตรวจหาบั๊กและเพิ่มเสถียรภาพ
ภาพรวมของ C3
- C3 เป็นภาษาโปรแกรมที่พัฒนาต่อยอดโดยอิงจาก ไวยากรณ์ (syntax) และ ความหมาย (semantics) ของภาษา C
- เป้าหมายคือทำให้ภาษาพัฒนาขึ้นโดยยังคงรูปแบบที่โปรแกรมเมอร์ C เดิมคุ้นเคย
- รองรับ operator overloading ที่แม่นยำและตรงวัตถุประสงค์
- สามารถแสดง การคำนวณเวกเตอร์ เมทริกซ์ และเลขทศนิยมคงที่ ได้อย่างเป็นธรรมชาติ โดยไม่ต้องมีโครงสร้าง overloading ที่ซับซ้อนแบบ C++
- รองรับ การเขียนโปรแกรมแบบอิงสัญญา ทำให้ระบุข้อกำหนดได้ทั้งในรันไทม์และคอมไพล์ไทม์
- ช่วยเสริมความเสถียรของโค้ดและความสอดคล้องของสเปก
- ผสานข้อดีของ การจัดการข้อผิดพลาดแบบอิง Result และ exception
- มอบโครงสร้างจัดการข้อผิดพลาดที่ผสานกับโค้ด C ได้อย่างเป็นธรรมชาติ
- รองรับ การตรวจสอบข้อมูลชนิด (type introspection) ทั้งในคอมไพล์ไทม์และรันไทม์
- อินไลน์แอสเซมบลี: สามารถ เขียน assembly ได้เหมือนโค้ดปกติ โดยไม่ต้องใช้สตริงหรือข้อกำหนดที่ซับซ้อน
- ใน โหมดดีบัก จะมีการแทรก การตรวจสอบขอบเขต (bound checks) และ การตรวจสอบค่า (value checks) ในรันไทม์ให้อัตโนมัติ
- ไลบรารีมาตรฐานของ C3 มี stack trace แบบละเอียดในดีบักบิลด์ มาให้เป็นค่าเริ่มต้น
- ช่วยให้ระบุตำแหน่งข้อผิดพลาดได้อย่างชัดเจน แทนข้อความ “segmentation fault” แบบกว้าง ๆ
ความสะดวกในการใช้งานและความปลอดภัย
- ใช้ Optionals เพื่อมอบ ความปลอดภัยในการจัดการ error และ null
- ไวยากรณ์ defer ช่วย ทำให้การจัดการคืนทรัพยากรเป็นอัตโนมัติ
- ใช้ slices และ foreach เพื่อ วนซ้ำอย่างปลอดภัย
- ใช้ contracts แบบอิงคอมเมนต์เพื่อ ระบุเงื่อนไขข้อจำกัดของโค้ด
- รองรับ การคืนหน่วยความจำอัตโนมัติ ในคอนเท็กซ์ @pool
Performance by default
- สามารถเขียน SIMD vector ได้โดยตรงเพื่อ ควบคุมระดับฮาร์ดแวร์
- รองรับการเลือก memory allocator หลายแบบเพื่อ ปรับจูนประสิทธิภาพอย่างละเอียด
- ใช้การออกแบบ การจัดการข้อผิดพลาดแบบไม่มีโอเวอร์เฮด
- ใช้ประโยชน์จากเวลาคอมไพล์ที่รวดเร็วและ การปรับแต่งด้วย LLVM backend
- มี inline assembly ที่ใช้งานง่าย
ไลบรารีมาตรฐานที่มีมาให้พร้อมใช้
- มี โครงสร้างข้อมูลมาตรฐาน รวมถึงคอนเทนเนอร์แบบไดนามิกและสตริง
- มี abstraction แบบข้ามแพลตฟอร์มเพื่อ รองรับการพกพาระหว่างแพลตฟอร์ม
- อนุญาตให้เข้าถึง แพลตฟอร์มเนทีฟ ได้เมื่อจำเป็น
ใช้ประโยชน์จากไลบรารี C หรือ C++ ที่มีอยู่เดิม
- C3 เข้ากันได้กับ C ABI อย่างสมบูรณ์ จึงไม่ต้องมี “ชนิดข้อมูลที่เข้ากันได้กับ C” หรือการประกาศฟังก์ชันแยกต่างหาก
- สามารถลิงก์โค้ด C จาก C3 ได้ และลิงก์โค้ด C3 จาก C ก็ได้
โมดูลนั้นเรียบง่าย
- ระบบโมดูล ที่เรียบง่ายและเข้าใจได้ทันที
- ค่าตั้งต้นถูกออกแบบไว้อย่างสมเหตุสมผลและไม่รบกวนการทำงานของนักพัฒนา
- มี การจัดการ namespace ผ่านโมดูล
- ใช้การควบคุมแบบชัดเจนเพื่อ ทำให้โครงสร้างการห่อหุ้มเรียบง่ายขึ้น
- สามารถกำหนด พฤติกรรมที่ใช้ร่วมกัน ผ่าน interface
- มีความสามารถ generic modules ที่ช่วยให้สร้าง generic type ได้อย่างเรียบง่ายและชัดเจน
- รองรับ การนำโครงสร้างกลับมาใช้ซ้ำ ผ่าน struct subtyping
Macros without a PhD
- สามารถเขียน compile-time macro ในรูปแบบคล้ายฟังก์ชันทั่วไปได้
- รองรับ macro ที่รับรู้ชนิดข้อมูล ซึ่งเข้าใจข้อมูลชนิดของโค้ด
- รองรับการสร้างโค้ดที่ชัดเจนและทรงพลังยิ่งกว่า C preprocessor
4 ความคิดเห็น
มีออกมาหลากหลายดีนะครับ LONG LIVE C-LANG !!!
แต่ถ้าต่อไปมี c4 ออกมาล่ะก็ จะได้รับความนิยมแบบระเบิดระเบ้อเลยไหมนะ...
เพราะ Zig มีการเปลี่ยนแปลงแบบ breaking changes ทุกปี แม้จะชอบตัวภาษา แต่ตอนนี้ก็ไม่ค่อยอยากหยิบมาใช้แล้วครับ
ในทางกลับกัน พอดูคำแนะนำของ c3 แล้ว โดยรวมให้ความรู้สึกแบบ c + go เลยทั้งอ่านและเขียนง่าย และรู้สึกว่าน่าจะเครียดกับการออกรุ่นใหม่น้อยกว่ามากนะครับ
ผมก็ช่วยสนับสนุนอยู่บ้าง... ช่วงนี้กำลังใช้อยู่แล้วรู้สึกว่าสนุกดี
ชอบตรงที่มันให้ความรู้สึกเหมือนตั้งใจแก้แค่จุดที่ใช้ C แล้วไม่สะดวก
เอกสารทางการยังดูไม่ค่อยสุกงอมเท่าไร
(ถ้าจะหาฟีเจอร์ต่าง ๆ บางทีก็ไปอธิบายไว้ในที่แปลก ๆ แบบไม่มีปี่มีขลุ่ยบ่อยมาก...)
ความเห็นจาก Hacker News
มันไม่ได้บังคับให้ใช้ memory model แบบใหม่ และก็ไม่ได้พยายามจะเป็นเหมือน C++
โดยเฉพาะ ความเข้ากันได้กับ ABI แบบสมบูรณ์ ทำให้สามารถเอาไฟล์ C3 ไปผสมใช้ในระบบบิลด์ C เดิมได้ทันทีโดยไม่ต้องเขียน binding
ขอชื่นชมวิสัยทัศน์ของผู้ดูแลที่มุ่งเน้นวิวัฒนาการมากกว่าการปฏิวัติ
น่าแนะนำเป็นภาษาที่ลองเรียนในช่วงสุดสัปดาห์ ดูทันสมัยกว่า C99 แต่ก็ยังให้ความรู้สึกคุ้นเคย
เหตุผลที่ฉันยังเลิก C ไม่ได้เสียทีคือ cstring กับ pointer ที่ไม่ถูก free
ตัว C เองไม่ได้เป็นภาษาที่อันตรายเท่ากับที่ implementation และ ABI ต่างหากที่อันตราย
ถ้าใช้ fat pointer, ปรับปรุง varargs, UBSan, MTE ฯลฯ ก็ถือว่าโอเคมากแล้ว
ถ้าคอมไพเลอร์ไม่จำเป็นต้องตรวจสอบ contract เสมอไป และเมื่อมีการละเมิดแล้วอาจกลายเป็น พฤติกรรมที่ไม่กำหนดไว้ ก็ไม่แน่ใจว่าจะเชื่อใจและใช้งานสิ่งนี้อย่างไรดี
เป็นฟีเจอร์ที่เท่มาก แต่ก็ดูเสี่ยงอยู่พอสมควร
จะเพิกเฉยต่อมัน ตรวจสอบตอนรันไทม์ หรือถือว่ามันเป็นจริงเสมอแล้วนำไปใช้ในการ optimize ก็ได้
ตัวอย่างเช่น เลือกตรวจสอบความถูกต้องของ pointer แต่ถือว่าเงื่อนไขเรื่องอินพุตเป็นเลขคี่เป็นข้อสมมติได้
ทีมขนาดใหญ่สามารถบังคับใช้ได้ และเครื่องมืออย่าง Visual Studio อาจแค่แสดงคำเตือน ทำให้ค่อย ๆ เรียนรู้และนำไปใช้ได้
กล่าวคือ เปิดไว้ตอนพัฒนา แล้วปิดตอน deploy เพื่อไม่ให้กระทบประสิทธิภาพได้
เงื่อนไขที่ต้องตรวจจริง ๆ ควรจัดการด้วยโค้ดภายในฟังก์ชันโดยตรง
จุดที่ต่างจาก C ได้แก่ ไม่มี header file, namespace แบบโมดูล, slice, operator overloading, generic module, การจัดการข้อผิดพลาดแบบ Result, และการตรวจสอบตอนรันไทม์ใน safe mode
ส่วนตัวฉันเสียดายที่ไม่มี function overloading, default parameter และ tuple return
ResultหรือExpectedว่า Optional ทำให้สับสนเพราะมันควรหมายถึง “T หรือ E” ไม่ใช่ “T หรือว่างเปล่า” ชื่อนี้ดูเหมือนจะไม่ถูกนัก
ลิงก์เอกสารที่เกี่ยวข้อง
Option<T>หรือResult<T, E>เพราะ ชนิดของ error ถูกจำกัดให้เป็นเพียงโค้ดจำนวนเต็มตัวเดียว ซึ่งเข้ากับแนวคิด “วิวัฒนาการ ไม่ใช่การปฏิวัติ” ได้ดี
ไวยากรณ์
type?ก็ดูเข้าใจง่ายเป็นการออกแบบที่ยังรักษาความหมายแบบ C เอาไว้ พร้อมลดภาระของ out param
เพราะ
Resultเองก็มีความหมายทั่วไปว่าเป็นค่าที่ส่งกลับอยู่แล้ว จึงอาจชวนสับสนได้เพลย์ลิสต์ YouTube
สิ่งที่น่าประทับใจคือทั้งสามภาษาไม่ได้มองกันเป็นคู่แข่ง แต่เป็นความสัมพันธ์แบบ แลกเปลี่ยนและเรียนรู้จาก trade-off ของกันและกัน
แต่มีการเพิ่มฟีเจอร์อย่าง macro และ reflection เข้ามาแทน
เพราะมันกินหน่วยความจำเท่ากับชนิดที่ใหญ่ที่สุด และย้าย flow ไปสู่การตรวจสอบชนิดตอนรันไทม์ ทำให้สูญเสียข้อดีของภาษาที่มี static type
ถ้าจำเป็นจริง ๆ ฉันมองว่าควรเขียนขึ้นมาใช้เองจะดีกว่า
ฉันเคยลงมือทำ generic, slice และ error propagation บน C เอง แต่ การสร้างคอมไพเลอร์นั้นซับซ้อนเกินไป
เพราะอย่างนั้นฉันเลยใช้ทั้ง C ที่ดัดแปลงเองและ Go ควบคู่กันไป
อุปสรรคในการเริ่มต้นต่ำมากจนถึงขั้น ทำ prototype ได้ภายในวันเดียว
เพราะมันคือ วิธีเดียวที่จะทำให้พาราไดม์ใหม่กลายเป็นความจริง
ภาษาต้องประสานทั้งไวยากรณ์ standard library tooling และ runtime เข้าด้วยกันจึงเป็นงานยาก แต่ก็ส่งผลต่ออนาคตได้มากเท่านั้น
และด้วย LLVM เขาจึงสามารถสร้างคอมไพเลอร์ใหม่ขึ้นมาได้
C ที่ดัดแปลงเองเพื่อใช้คนเดียวก็ไม่เป็นไร แต่ถ้าจะทำงานร่วมกับคนอื่นหรือใช้ไลบรารีภายนอก ก็จำเป็นต้องมีภาษากลางร่วมกัน
และการเรียกข้อยกเว้นว่า “Excuses” ก็ดูน่ารักและมีไหวพริบดี
โดยเฉพาะการมีลิงก์ Discord อยู่ใน navigation ยิ่งทำให้ความรู้สึกนั้นชัดขึ้น