- หัวใจสำคัญของประสิทธิภาพการเขียนโปรแกรมคือ ระบบนิเวศของไลบรารีที่อุดมสมบูรณ์มากกว่าตัวภาษาเอง
- เฟรมเวิร์กที่ ใช้ความสามารถขั้นสูงของภาษา อย่าง Ruby on Rails มอบประสิทธิภาพสูงได้แม้กับผู้ที่ไม่ใช่ผู้เชี่ยวชาญ
- แต่เพราะ ข้อจำกัดเชิงโครงสร้างของภาษา จึงยากที่จะสร้างเฟรมเวิร์กระดับ Rails ด้วย Java หรือ C
- การออกแบบภาษาเป็นตัวกำหนดโดยตรงถึงรูปแบบและความซับซ้อนของไลบรารีที่สามารถเขียนได้ และนี่คือเป้าหมายที่แท้จริงของวิวัฒนาการภาษา
- ภาษา Stanza แสดงให้เห็นความสำคัญของการออกแบบภาษาที่ทำให้สามารถสร้างไลบรารีทรงพลังและใช้งานง่ายได้จากมุมมองนี้
ความสัมพันธ์ระหว่างภาษาโปรแกรมกับไลบรารี
- ภาษาโปรแกรมส่วนใหญ่มีองค์ประกอบพื้นฐานคล้ายกัน เช่น ตัวแปร อาร์เรย์ ลูป และฟังก์ชัน
- บางภาษามีความสามารถขั้นสูงอย่าง first-class functions หรือ coroutines แต่ผู้ใช้ที่ไม่ใช่ผู้เชี่ยวชาญมักไม่ได้ใช้งานสิ่งเหล่านี้มากนัก
- สำหรับนักพัฒนาจำนวนมาก ปัจจัยที่ช่วยเพิ่มประสิทธิภาพคือ ไลบรารีมากกว่าตัวภาษา
- ตัวอย่างเช่น Ruby on Rails ช่วยให้สร้างเว็บแอปพลิเคชันที่ทำงานกับฐานข้อมูลได้อย่างง่ายดาย
- ด้วย Rails ผู้คนจึงมักชอบ เฟรมเวิร์กมากกว่าตัวภาษา Ruby เอง
ปฏิสัมพันธ์ระหว่าง Ruby on Rails กับความสามารถของภาษา
- Rails ใช้ความสามารถหลากหลายของ Ruby เช่น metaprogramming, runtime evaluation, first-class functions, garbage collection
- ตัวอย่าง: ActiveRecords ใช้ metaprogramming ส่วนระบบเทมเพลตใช้ runtime evaluation
- การจัดการอีเวนต์ถูกทำผ่านการส่ง first-class functions เป็น callback
- ใน Java หรือ C ความสามารถเหล่านี้มีไม่พอ จึง ไม่สามารถสร้างเฟรมเวิร์กระดับ Rails ได้
- metaprogramming ของ Java ไม่ทรงพอสำหรับการสร้าง ActiveRecords
- ดังนั้น Rails จึงเกิดขึ้นได้เพราะโครงสร้างของภาษา Ruby และ การออกแบบภาษาเป็นตัวกำหนดความเป็นไปได้ของไลบรารี
การออกแบบภาษากำหนดรูปแบบของไลบรารี
- ภาษา C รองรับการนำกลับมาใช้ซ้ำผ่านเพียงการประกาศและเรียกใช้ฟังก์ชัน ทำให้ไลบรารีของ C ส่วนใหญ่อยู่ในรูปของ ชุดฟังก์ชัน
- Ruby รองรับ first-class functions จึงสามารถเขียนว่า “เมื่อปุ่มถูกคลิกให้ทำงานนี้” ได้อย่างกระชับ
- ในทางกลับกัน Java ต้อง นิยามคลาส handler ทำให้โค้ดซับซ้อนขึ้น
- พลังในการแสดงออกของภาษาส่งผลโดยตรงต่อ โครงสร้างและความง่ายในการใช้งานของไลบรารี
ซอฟต์แวร์เชิงโต้ตอบและการมาของเฟรมเวิร์กที่ขยายได้
- ในยุคคอมพิวติ้งแบบแบตช์ของทศวรรษ 1970 ไลบรารีที่เน้นฟังก์ชันก็เพียงพอแล้ว
- แต่ในซอฟต์แวร์เชิงโต้ตอบสมัยใหม่ จำเป็นต้องมี ไลบรารีที่ขยายได้
- ใน GUI หรือระบบที่ขับเคลื่อนด้วยอีเวนต์ จำเป็นต้องมีโครงสร้างแบบ “เมื่อผู้ใช้คลิก ให้รันโค้ดของฉัน”
- Java และ C++ รองรับการขยายด้วย inheritance และ method overriding และโครงสร้างลักษณะนี้ก็พัฒนาไปเป็น เฟรมเวิร์ก
ฉากหลังของการออกแบบ Stanza และข้อจำกัดของภาษา
- แรงจูงใจในการออกแบบ Stanza เริ่มจากความยากในการ เขียนไลบรารีสำหรับการเขียนโปรแกรมเกมที่ใช้งานง่าย ใน Java
- ใน Java ต้องแสดง concurrency ด้วย state machine
- ส่วน Scheme รองรับ continuation จึงทำให้สร้างสิ่งนี้ได้อย่างเป็นธรรมชาติกว่า
- แต่ Scheme ไม่รองรับการตรวจสอบชนิดแบบสแตติก จึง มีประสิทธิภาพในการดีบักต่ำ
- ปัจจุบัน ภาษาส่วนใหญ่ยังไม่สามารถ ขยายระบบชนิดผ่านไลบรารี ได้
- Stanza มี ระบบชนิดแบบเลือกใช้, garbage collection, ระบบอ็อบเจ็กต์แบบ multimethod-based
- แต่ก็ยังไม่สามารถเขียนระบบอ็อบเจ็กต์แบบกำหนดเองขึ้นใหม่ได้
เป้าหมายของภาษาและทิศทางการวิจัย
- เป้าหมายของภาษาโปรแกรมเอนกประสงค์คือ รองรับการสร้างไลบรารีที่ทรงพลังและใช้งานง่าย
- ยิ่งภาษาทรงพลังมากเท่าไร การใช้งานไลบรารีก็ยิ่งกระชับมากขึ้นเท่านั้น
- เมื่อโค้ดใช้ไลบรารีที่ออกแบบมาอย่างดี มันจะ อ่านได้เป็นธรรมชาติราวกับประโยคที่ใช้สั่งงานเพื่อนร่วมงาน
- งานวิจัยอย่าง Racket, Shen และ meta object protocol กำลังสำรวจ ระบบชนิดและระบบอ็อบเจ็กต์ที่ขยายได้
- ท้ายที่สุด ภาษาแต่ละภาษาถูกจำแนกได้จาก “ใช้ไลบรารีแบบใดได้ และแบบใดใช้ไม่ได้”
- เบื้องหลังไลบรารีที่งดงามคือ งานวิจัยและความพยายามด้านการออกแบบภาษาที่สั่งสมมาหลายทศวรรษ
1 ความคิดเห็น
ความเห็นจาก Hacker News
ตัวอย่างที่ดีที่สุดคือ Prolog มักถูกเรียกว่าเป็นภาษาตัวแทนของการเขียนโปรแกรมเชิงตรรกะ แต่จริง ๆ แล้วแทบจะเป็นเพียง ชุดของอัลกอริทึมหลายแบบ และสามารถนำไปทำเป็นไลบรารีของแต่ละภาษาได้ แค่มีรูปแบบไวยากรณ์ของ Prolog ให้สอดคล้องกับไวยากรณ์ของแต่ละภาษาก็น่าจะเพียงพอ
เมื่อ 10 ปีก่อนผมเป็นแฟน Scala มาก แนวคิด “Scalable Language” ที่สามารถสร้าง DSL ภายใน type system ได้เป็นอะไรที่ดึงดูดมาก แต่พอ community เริ่มใช้มันเหมือน Haskell บน JVM ผมก็หมดความสนใจ ทุกวันนี้ผมคาดหวังว่าเทคโนโลยีอย่าง WASM หรือ Graal จะช่วยให้การเลือกภาษายืดหยุ่นขึ้น หลายกรณีใช้ JS ก็พอแล้ว แต่ก็ดีที่เวลาจำเป็นยังมีตัวเลือกให้ใช้ภาษาระดับล่างอย่าง Rust ได้
ถ้ามี ภาษาสคริปต์แบบมี type ที่เอามาแทน bash ได้ก็คงดี ผมลองเขียนสคริปต์ parser JSON ง่าย ๆ ด้วย Elixir แล้วรู้สึกว่าใช้ได้เลย
#!/usr/bin/env ocamlได้เลย เพียงแต่ยังไม่มีความสามารถติดตั้ง dependency ภายนอกอัตโนมัติจากไฟล์เดียวภาษาและไลบรารี ไม่ได้เป็นสิ่งที่排斥กัน ไลบรารีบางตัวทำงานแทบไม่ต่างจากภาษา และในทางกลับกัน ภาษาบางภาษาก็ถูกออกแบบมาเพื่อไลบรารีเฉพาะด้วย เช่น Julia เป็นตัวอย่างที่บาลานซ์ระหว่างประสิทธิภาพกับความสะดวกในการใช้งานได้ดี คุณสามารถเขียนโค้ดประสิทธิภาพสูงด้วย Julia โดยตรง และได้ประโยชน์จาก การคอมไพล์แบบ type-specialized ระดับ JIT เพื่อให้รันได้อย่างเหมาะสม แม้โมเดลภายนอกจะดูเป็นแค่การเรียกฟังก์ชันธรรมดา แต่ภายในซับซ้อนและชาญฉลาดมาก
Raku ถูกออกแบบให้เป็นโครงสร้างที่เชื่อมหลายภาษาย่อย (slang) เข้าด้วยกัน เช่น regex, PEG, quoting ฯลฯ ถูกจัดการเป็นมินิภาษาของตัวเอง และใช้ Slangify เพื่อเพิ่ม DSL ของตัวเองได้ง่าย
ครั้งหนึ่งมีนักพัฒนาอาวุโสคนหนึ่งพูดว่า “ถ้าเห็น Rails ในเรซูเม่ก็โยนทิ้งทันที” มันยิ่งทำให้รู้สึกว่า การตัดสินคนจากภาษา เป็นเรื่องโง่แค่ไหน
ท้ายที่สุดแล้ว ภาษาหรือไลบรารีก็คือ เครื่องมือสื่อสารทั้งกับเครื่องและกับคน เครื่องสื่อสารผ่านบิตและแรงดันไฟฟ้า ส่วนคนสื่อสารผ่าน เจตนาและแนวคิด เพราะฉะนั้นถ้าภาษาหรือไลบรารีช่วยให้คนสื่อสารได้ชัดและเร็วพอ จะเป็นภาษาหรือไลบรารีก็ไม่สำคัญ Rails หรือ Stanza ก็เหมือนกัน ถ้ามันเหมาะกับจุดประสงค์และทีมเข้าใจได้ง่าย นั่นก็คือคำตอบที่ถูกต้อง
ผมมองว่า “ไลบรารีก็คือภาษาสุดท้ายในสายโซ่” ตัวอย่างเช่น Ruby on Rails คือภาษาสำหรับเว็บเซอร์วิสที่ยอดเยี่ยมซึ่งอยู่บนฐานของ Ruby Ruby และ Rails พัฒนาร่วมกันเพื่อเกื้อหนุนกันเอง สุดท้ายแล้วผมคิดว่า การเขียนโปรแกรมคือกระบวนการแปลภาษาต่อเนื่องหลายชั้น
คำพูดที่ว่า “ยิ่งภาษาทรงพลังเท่าไร การใช้ไลบรารีก็ยิ่งง่ายขึ้น” นั้นจริง สมัยก่อน Java ทำเฟรมเวิร์กอย่าง Express ได้ยาก
ถ้าเป็นเว็บเฟรมเวิร์กสำหรับภาษา C ก็มี PHP ไงล่ะ ;)