1 คะแนน โดย GN⁺ 2025-10-05 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เปรียบเทียบความแตกต่างและลักษณะเด่นที่พบจากการใช้ Ada และ Rust แก้โจทย์ Advent of Code
  • วิเคราะห์ความต่างของการออกแบบภาษาและวิธีเขียนโปรแกรมจริงของทั้งสองภาษา โดยเน้นที่ ความปลอดภัย และความน่าเชื่อถือ
  • ความแตกต่างปรากฏชัดจากหลายมุมมอง เช่น ไลบรารีมาตรฐาน การมีฟีเจอร์ในตัว ความต่างด้านประสิทธิภาพ และรูปแบบการจัดการข้อผิดพลาด
  • อธิบายกรณีตัวอย่างที่พบจริงระหว่างการเขียนและใช้งาน ผ่านโค้ดตัวอย่างด้าน ความเป็นโมดูลาร์ เจเนอริก ลูป และการจัดการข้อผิดพลาด
  • ประสบการณ์พัฒนาที่แตกต่างกันเห็นได้ชัดจากรูปแบบ static typing การจัดการอาร์เรย์ และอินเทอร์เฟซสำหรับจัดการข้อผิดพลาด

บทนำและจุดประสงค์

  • ระหว่างการแก้โจทย์ Advent of Code (ต่อไปจะเรียกว่า AoC) เดิมผู้เขียนใช้เพียง Ada แต่ตั้งแต่ปี 2023 ก็เริ่มเขียนคำตอบด้วย Rust และ Modula-2 ด้วย จึงได้เปรียบเทียบโดยตรง
  • เมื่อนำโซลูชันที่เดิมเน้น Ada มาเขียนใหม่ด้วย Rust จึงสัมผัสได้ถึงความแตกต่างเชิงโครงสร้างและ แนวทางเฉพาะตัว ของทั้งสองภาษา
  • มีจุดประสงค์เพื่อทำให้เห็นความแตกต่างในการใช้งานจริงอย่างชัดเจน ในแง่ความปลอดภัยของโค้ด ความน่าเชื่อถือ และมุมมองด้านการออกแบบภาษา

เวอร์ชันภาษาที่ใช้ในการเปรียบเทียบ

  • Ada 2022 (อ้างอิงกฎบางส่วนของ Spark 2014 ตามความจำเป็น)
  • Rust 2021 (การเปรียบเทียบหลักอิงจาก Rust 1.81.0)

ฟีเจอร์ที่ไม่ได้รวมและเกณฑ์การเปรียบเทียบ

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

พื้นฐานและมุมมองของผู้เขียน

  • ผู้เขียนเป็นผู้ใช้ ที่ไม่ใช่เจ้าของภาษา ทั้ง Ada และ Rust โดยมีพื้นฐานจากภาษาในยุค 1980 อย่าง C/C++, Pascal, Modula-2 เป็นต้น
  • ส่งผลให้ สไตล์โค้ด อาจแตกต่างจากแนวทางสมัยใหม่หรือ idiom ทั่วไป
  • โค้ดอาจไม่ใช่ implementation ที่ดีที่สุดเสมอไป และในบางสถานการณ์อาจเลือกวิธีแก้ที่ตรงไปตรงมาหรือไม่เป็นไปตามธรรมเนียม

ตำแหน่งของ Ada และ Rust

  • Ada ยังคงเป็นภาษาสำหรับการพัฒนาระบบ/embedded ที่มีความปลอดภัยและความน่าเชื่อถือสูงมาก โดย ให้ความสำคัญกับความอ่านง่ายของโค้ด
  • Rust มีจุดแข็งด้าน memory safety และ system programming และได้รับการจัดให้เป็น “ภาษาที่นักพัฒนาชื่นชอบมากที่สุด” หลายปีในผลสำรวจนักพัฒนาของ Stack Overflow
  • Ada เป็น ภาษาระดับสูงแบบอเนกประสงค์ ที่มีจุดเด่นด้านการอ่านและการบำรุงรักษา
  • Rust มุ่งไปที่ การพัฒนาโปรแกรมระบบระดับล่าง พร้อมสร้างวัฒนธรรมการเขียนโปรแกรมอย่างปลอดภัยผ่านการจัดการหน่วยความจำแบบชัดเจน และชนิดข้อผิดพลาด/ตัวเลือกอย่าง error/option

เปรียบเทียบด้านความปลอดภัยและลักษณะเชิงโครงสร้าง

  • Ada

    • เป็นมาตรฐาน ISO (มีสเปกที่เข้มงวด)
    • ประกาศชนิดข้อมูลให้เหมาะกับลักษณะของปัญหาได้ง่าย (เช่น ช่วงค่า จำนวนหลัก ฯลฯ)
    • อนุญาตให้ index ของอาร์เรย์ไม่จำเป็นต้องเป็นตัวเลข
    • มีข้อกำหนดที่เข้มงวดยิ่งขึ้นใน Spark
  • Rust

    • สเปกอิงจากเอกสารทางการ (Reference) และตัวคอมไพเลอร์เป็นหลัก
    • การประกาศชนิดข้อมูลผูกกับ machine type (เช่น f64, u32)
    • การ index อาร์เรย์เหมาะกับชนิดตัวเลขโดยธรรมชาติ

สรุปตารางฟีเจอร์/การมีในตัวที่สำคัญ

  • มีความต่างในด้านการรองรับ การตรวจสอบขอบเขตอาร์เรย์, generic container, concurrency, label loop, pattern matching เป็นต้น
  • Ada ใช้การจัดการข้อผิดพลาดแบบ Exception ขณะที่ Rust ใช้การคืนค่าผ่านชนิด Result/Option
  • Rust โดดเด่นด้วยการรองรับ macro, pattern matching, ความเป็นฟังก์ชันแบบบริสุทธิ์ เป็นต้น
  • Ada รองรับ การออกแบบแบบมีสัญญา และ Spark รองรับการตรวจสอบ DBC (Design By Contract) ตั้งแต่คอมไพล์ไทม์
  • ในด้าน memory safety นั้น Rust และ Spark มีการบังคับใช้ ขณะที่ Ada อนุญาตให้ใช้ Null pointer ได้

เปรียบเทียบประสิทธิภาพและเวลาในการรัน

  • โดยทั่วไป Rust มีชื่อเสียงว่า รันเร็วแต่คอมไพล์ช้า ส่วน Ada ตรงกันข้ามคือ คอมไพล์เร็วกว่า แต่การรันอาจช้ากว่าเล็กน้อยขึ้นอยู่กับการตรวจสอบระหว่างรัน
  • จากผล benchmark Rust เกิด overflow ในโจทย์ day24 เพราะข้อจำกัดของชนิด f64 แต่ Ada สามารถกำหนดชนิดระดับสูงอย่าง digits 18 ได้ ทำให้เลือก machine type ที่เหมาะสมโดยอัตโนมัติและหลีกเลี่ยง overflow พร้อมแสดงประสิทธิภาพที่ดีกว่า
  • Rust จำเป็นต้องใช้ f128 ที่ยังไม่เสถียรหรือไลบรารีภายนอก ขณะที่ Ada ได้เปรียบเพียงแค่กำหนดชนิดข้อมูลให้ตรงกับสเปกของคอมไพเลอร์

การจัดการไฟล์และ error handling (กรณีศึกษา 1)

การจัดการไฟล์ใน Ada

  • ใช้ Ada.Text_IO เป็นพื้นฐาน
  • สามารถเปิดไฟล์อย่างชัดเจน อ่านทีละบรรทัด และจัดการบรรทัดตามช่วงหรือค่าตำแหน่งที่ต้องการได้อย่างค่อนข้างตรงไปตรงมา
  • เมื่อเกิดข้อผิดพลาด มักถูกจัดการด้วย exception มากกว่าการแสดงข้อความผิดพลาดที่ชัดเจน และความเป็นไปได้ที่จะเกิดข้อผิดพลาดไม่ปรากฏในลายเซ็นของฟังก์ชัน

การจัดการไฟล์ใน Rust

  • ใช้ std::fs::File และ BufReader
  • ตอนเปิดไฟล์จะคืนค่าเป็นชนิด Result ทำให้เห็นความเป็นไปได้ของข้อผิดพลาดอย่างชัดเจน
  • ไม่รองรับการเข้าถึง index ของตัวอักษรโดยตรง ต้องจัดการผ่าน Iterator เท่านั้น
  • ใช้เครื่องมือเชิงฟังก์ชันและเชิงวนซ้ำเป็นหลัก เช่น map, filter, collect, sum รวมถึงมี macro หลากหลาย (เช่น include_str!)
  • สามารถประกาศข้อผิดพลาดไว้ชัดเจนในชนิดค่าที่คืน ทำให้การส่งต่อข้อผิดพลาดในระดับฟังก์ชันมีความชัดเจน

ความเป็นโมดูลาร์และเจเนอริก (กรณีศึกษา 2)

ความเป็นโมดูลาร์ของ Ada

  • แยกสเปก (interface) และ implementation อย่างชัดเจนด้วย package
  • เสริมความเป็นโมดูลาร์ด้วย subpackage และการใช้ไวยากรณ์ use/rename เพื่อปรับความอ่านง่าย
  • รองรับ generic ของ package โดยทำให้ทั้งชนิดข้อมูล ค่าคงที่ และทั้ง subpackage เป็นแบบทั่วไปได้

ความเป็นโมดูลาร์ของ Rust

  • จัดโมดูลด้วยระบบ mod/crate และตัวสร้างเอกสารช่วยทำให้การแยกสเปกและ implementation เป็นอัตโนมัติ
  • มีการกำหนดสิทธิ์เข้าถึงแบบ pub/private ในเชิงประกาศ
  • ใช้ use/as เพื่อ import และเปลี่ยนชื่อ
  • รองรับ การทดสอบในตัว โดยสามารถประกาศ test module ในโค้ด สั่ง build และรันอัตโนมัติได้

เจเนอริก

  • Ada รองรับเจเนอริกเฉพาะในระดับ package/procedure (ไม่รองรับชนิดข้อมูลเดี่ยว ๆ)
  • Rust สามารถใช้เจเนอริกกับ ชนิดข้อมูลเองได้โดยตรง (แนว template)
  • Ada สามารถแสดงคุณลักษณะเพิ่มเติมอย่างช่วงของชนิดข้อมูลได้ชัดเจนผ่าน range type, subtype ขณะที่ Rust ใช้ค่าคงที่ของอินสแตนซ์

เปรียบเทียบชนิด enum (กรณีศึกษา 3)

  • Ada รองรับทั้ง การประกาศแบบกระชับ และทำให้ชนิดนั้นใช้งานเป็นชนิดไม่ต่อเนื่อง มีลำดับ และใช้กับลูป/ดัชนีได้โดยอัตโนมัติ
  • enum ของ Rust แม้รูปแบบการประกาศจะคล้ายกัน แต่การเข้าถึงผ่าน pattern matching หรือการวนซ้ำจำเป็นต้องเขียนอย่างชัดเจนมากกว่า

บทสรุป

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

1 ความคิดเห็น

 
GN⁺ 2025-10-05
ความคิดเห็นบน Hacker News
  • น่าเสียดายที่แม้ Ada จะมีไอเดียที่ดีมากอยู่หลายอย่าง แต่กลับถูกใช้เป็นส่วนใหญ่เฉพาะในงานที่ความปลอดภัยมีความสำคัญสูงมากเท่านั้น โดยเฉพาะความสามารถในการจำกัดช่วงค่าของชนิดตัวเลข ซึ่งมีประโยชน์มากในการป้องกันบั๊กบางประเภท Spark Ada ก็เรียนรู้ได้ง่ายและนำไปใช้กับการพัฒนาซอฟต์แวร์ที่ต้องสอดคล้องกับ SIL 4 (มาตรฐานความปลอดภัยซอฟต์แวร์ที่เข้มงวดที่สุด) ได้ไม่ยาก หลายทศวรรษที่ผ่านมาอุตสาหกรรมซอฟต์แวร์วิ่งไปในแนวทาง “โตให้เร็วก่อน ความเสถียรไว้ทีหลัง” แต่ตอนนี้เริ่มรู้สึกได้ว่ากำลังมีแนวโน้มกลับมาสู่การพัฒนาซอฟต์แวร์ที่ปลอดภัยอีกครั้ง หวังว่าบทเรียนด้านความปลอดภัยที่สั่งสมมาจะต่อยอดไปเป็นภาษาที่ดีกว่าเดิม เพราะในความเป็นจริง ไอเดียดี ๆ มักซ่อนอยู่ในภาษากลุ่มเล็กแล้วค่อย ๆ หายไป
    • พอทำซอฟต์แวร์มานานจะรู้สึกว่ามีการ “ประดิษฐ์ล้อขึ้นใหม่” กันบ่อยมาก Ada กับ Rust คล้ายกันตรงที่ต่างก็ไล่ตามเรื่องความปลอดภัย แต่คำนิยามและขอบเขตของความปลอดภัยนั้นต่างกัน Rust ไล่ตามความปลอดภัยที่สำคัญบางแบบอย่างเข้มข้นและเฉพาะทางมาก ส่วน Ada มีคำนิยามของความปลอดภัยที่กว้างและเป็นรูปธรรมกว่า ตอนผมเรียน Ada ช่วงต้นยุค 90 คำวิจารณ์ที่พบบ่อยที่สุดคือภาษานี้ใหญ่และซับซ้อนเกินไปจนทำให้พัฒนาช้า (ตอนนั้นคอมไพเลอร์ Ada 83 ที่ผ่านการรับรองมีราคาต่อคนราว 20,000 ดอลลาร์เมื่อคิดเป็นมูลค่าปัจจุบัน) แต่ยุคสมัยเปลี่ยนไปแล้ว จนทุกคนยอมรับว่าภาษาใหญ่และซับซ้อนอย่าง Rust เป็นสิ่งจำเป็นสำหรับการเขียน concurrent programming ที่ปลอดภัยจริง ๆ
    • Nim ก็รองรับ subrange ที่ได้รับแรงบันดาลใจจาก Ada และ Modula เพื่อจำกัดช่วงค่าของชนิดข้อมูล
      type
        Age = range[0..200]
      
      let ageWorks = 200.Age
      let ageFails = 201.Age
      
      ตอนคอมไพล์จะขึ้น error ว่า 201 แปลงเป็นชนิด Age ไม่ได้
      ลิงก์อธิบาย Nim Subranges
    • Ada (อิงตาม GNAT) รองรับการวิเคราะห์หน่วย/มิติทางกายภาพในช่วงคอมไพล์ (กล่าวคือ การตรวจหน่วย) ซึ่งใช้งานได้จริงมากในงานวิศวกรรม จึงน่าสงสัยว่าทำไมภาษาอื่น ๆ ถึงมีฟีเจอร์สำคัญแบบนี้ให้แค่ผ่านไลบรารีภายนอก
      เอกสารที่เกี่ยวข้อง
    • ใน C++ ก็สามารถสร้างชนิดตัวเลขที่จำกัดช่วงค่าได้ง่ายด้วยโค้ดเอง (แม้ไม่มีใน standard library แต่เขียนเองได้ไม่ยาก) การตรวจความปลอดภัยบางอย่างทำได้ตั้งแต่คอมไพล์ไทม์ ไม่จำเป็นต้องรันไทม์ อยากให้ทุกภาษารองรับฟีเจอร์แบบนี้เป็นมาตรฐาน
    • สิ่งที่น่าเสียดายที่สุดใน Ada คือแนวทางที่ชัดเจนต่อ object-oriented programming (OOP) ภาษาส่วนใหญ่มักยัดแนวคิด OOP ทั้งหมดไว้ในก้อนเดียวชื่อว่า “คลาส” แต่ Ada เปิดให้เลือกใช้ message passing, dynamic dispatch, subtyping, generic ฯลฯ แยกกันได้ตามต้องการ และผมชอบมากที่แต่ละฟีเจอร์พวกนี้ประกอบเข้ากันได้อย่างสวยงาม
  • ผู้เขียนกล่าวถึงความต่าง เช่น Ada มีข้อกำหนดมาตรฐานอย่างเป็นทางการ แต่ Rust ไม่มี อย่างไรก็ตาม ในมุมผู้ใช้จริง สิ่งที่สำคัญกว่านั้นคือการยอมรับของภาษา/ระบบนิเวศ (tooling, ไลบรารี, คอมมูนิตี้) ถึง Ada จะประสบความสำเร็จในสายอากาศยาน/งานด้านความปลอดภัย และเหมาะกับ AOC หรือ embedded ระดับล่าง แต่ในโปรเจกต์จริง (distributed systems, คอมโพเนนต์ของ OS ฯลฯ) ปัจจัยอย่าง data format, protocol, การรองรับจาก IDE, การทำงานร่วมกับเพื่อนร่วมทีม มีน้ำหนักมากกว่า สุดท้ายแล้วเวลาเลือกภาษาตั้งแต่แรก เรื่องแวดล้อมเหล่านี้แหละที่ชี้ขาด
    • ช่วงหลัง Rust ก็ได้รับเอกสารสเปกที่ Ferrocene บริจาค ซึ่งอ้างอิงสไตล์ข้อกำหนดของ Ada เช่นกัน เปิดเผยสาธารณะและเข้าไปดูได้
      Rust สเปก
    • ทั้ง Rust และ Ada ก็ยังไม่แข็งแรงนักในความหมายของ “ข้อกำหนดเชิงรูปแบบ (formal)” แบบเข้มงวดจริง ๆ (คือเอกสารที่พิสูจน์เชิงกลได้) แม้แต่ Spark Ada เองก็ยังตั้งอยู่บนสมมติฐานทางความหมายของภาษาอยู่ และสิ่งนี้เองก็ยังไม่ใช่รูปแบบที่เป็นทางการสมบูรณ์และอ่านได้โดยเครื่อง
    • นักพัฒนาซอฟต์แวร์ควบคุมอากาศยานก็คงตอบว่า “ถ้าเป็นเรื่องที่ไม่สำคัญในสภาพแวดล้อมจริงของโลกจริง กระบวนการของเราก็คงถือว่าเกินไปจริง” ที่จริงแล้ว ในงานสายความปลอดภัยสูง ภาษาและกระบวนการที่เข้มงวดแบบ Ada กลับเป็นมาตรฐานด้วยซ้ำ
  • ผมประทับใจที่แม้ Ada จะด้อยกว่า Rust ในบางความสามารถด้านชนิดข้อมูล แต่ในแง่ความอ่านง่ายของโค้ด Ada กลับทำได้ดีกว่าหลายครั้ง บทความเปรียบเทียบนี้ไม่ได้พูดถึงความเร็วของคอมไพเลอร์เลย และเรื่องที่ Ada เคยถูกมองว่าเป็นภาษาซับซ้อนก็อาจเป็นเรื่องในอดีต เพราะถ้าเทียบกับ Rust ยุคนี้ก็อาจไม่ใช่แบบนั้นอีกแล้ว อ่านบทความนี้แล้วทำให้อยากลองทำโปรเจกต์จริงด้วย Ada
    • อยากรู้ว่า “ข้อเสียด้านชนิดข้อมูล” หมายถึงอะไรแน่ เพราะจากประสบการณ์ของผม Ada มี type system ที่ expressive มาก มีทั้งชนิดกำหนดช่วงค่าเองได้, อาร์เรย์ที่ใช้ enum ตามใจเป็นดัชนีได้, การกำหนด operator ตามชนิด, การเพิ่มการตรวจตอนคอมไพล์/รันไทม์/precondition/postcondition ให้กับชนิดได้ รวมถึง discriminated record, structure representation clause ฯลฯ มองว่าไม่ใช่ข้อเสีย แต่เป็นความสามารถที่ทรงพลังมากกว่า
  • อยากพูดถึงความต่างเรื่องสตริงระหว่าง Ada กับ Rust Ada ถูกออกแบบตั้งแต่ต้นยุค 1980 โดยถือว่าอาร์เรย์ของ character คือ “สตริง” จึงทำดัชนีกับมันแบบอาร์เรย์ไบต์ได้ง่าย ส่วน Rust ถูกออกแบบโดยคำนึงถึง Unicode เป็นพื้นฐาน ดังนั้นสตริงของ Rust คือ UTF-8 encoded หรือพูดอีกอย่างคือเป็น ‘ข้อความ’ จริง ๆ เพราะฉะนั้น Ada จึงสุ่มเข้าถึงด้วยดัชนีแบบอาร์เรย์ได้ แต่ Rust มีแนวคิดเรื่องสตริงต่างออกไป และถ้าต้องการก็เลือกแปลงเป็นอาร์เรย์ไบต์ธรรมดาได้
    • สตริง Unicode ที่มีมาในตัวของ Ada โดยทั่วไปคืออาร์เรย์แบบ UTF-32 ต่างจาก Rust ตรงที่มันไม่มี UTF-8 literal ให้โดยตรง และต้องแปลงมาจากอาร์เรย์ขนาด 8/16/32 บิต
    • สตริงของ Rust ก็ทำ indexing ได้ เพียงแต่ Rust ไม่ปฏิบัติต่อสตริงเหมือนอาร์เรย์ทั่วไป และมักใช้ sub-string slice เป็นหลัก ถ้าตัดไป index กลางอักขระตัวหนึ่งจะเกิด panic (กรณีละเมิดขอบเขตของค่าการเข้ารหัส Unicode) ถ้าอย่าง AoC ที่ใช้แค่ ASCII เสมอ การใช้ byte slice ผ่าน [u8] หรือเมธอด str::as_bytes จะเหมาะกว่า
  • คำพูดของผู้เขียนที่ว่า Rust “ไม่รองรับ concurrent programming เป็นพื้นฐาน” ฟังดูแปลกสำหรับผม เพราะ Rust มีความสามารถด้าน thread ฝังมาในภาษาอยู่แล้ว และจริง ๆ ใช้ง่ายกว่า async เสียอีก ปัญหาจะมีแค่กรณีที่ต้องใช้ thread จำนวนมากจนชนข้อจำกัดด้านทรัพยากร แต่สำหรับซอฟต์แวร์ส่วนใหญ่ built-in thread ก็เพียงพอแล้ว
    • (ในฐานะคนที่ไม่ได้ใช้ Rust อยากรู้จริง ๆ) ใน Rust การจัดการ cancel ระหว่าง thread กับ async ต่างกันอย่างไร และต่างจาก async ของภาษาอื่นอย่างไร ใน C++, Python, C# การจัดการหยุดหรือยกเลิกใน async ดีกว่า thread มาก ใน Rust ได้ยินมาว่าเพราะไม่ได้จัดการการยกเลิก/หยุดด้วย exception จึงยิ่งยากขึ้น เลยอยากรู้ประสบการณ์จริงในงาน และก็อยากฟังด้วยว่า Ada จัดการเรื่องนี้อย่างไร
    • อยากรู้ว่าตรงไหนคือเส้นแบ่งที่ work-stealing scheduler อย่าง Tokio เร็วกว่าการหมุน thread หลายตัวแบบธรรมดาจริง ๆ ผมคิดว่ามันคล้ายกับอาร์เรย์ง่าย ๆ (เช่น VecMap) ที่เร็วเมื่อมีจำนวนสมาชิกน้อย แต่พอเกินจุดหนึ่งไปแล้วโครงสร้างข้อมูลแบบอื่นจะมีประสิทธิภาพกว่า อยากรู้ว่าจริง ๆ แล้ว work-stealing เริ่มได้เปรียบตั้งแต่จุดไหน
    • ในโลกความเป็นจริง เหตุผลหลักที่ต้องใช้ Async คือ third-party crate ที่ใช้อยู่เป็น Async อยู่แล้ว (เช่น Reqwest ต้องใช้ Tokrio) ถ้าจะยืนกรานใช้เฉพาะแบบไม่ Async ในการพัฒนาแอประดับสูง สุดท้ายก็มักไปต่อไม่ไหว
    • บนแพลตฟอร์มที่รองรับ thread ได้ไม่ดี (เช่น WASM, embedded ฯลฯ) Async กลับเหมาะกว่า สถานการณ์ที่มีคนหลายแสนเข้าบล็อกพร้อมกันนั้นไม่ค่อยสมจริงนัก แต่การเอาสถานการณ์แบบนี้มาอ้างเพื่อยืนยันความจำเป็นของ Async ก็ดูจะพูดเกินจริงไปหน่อย
  • น่าสนใจที่ Ada ก็มีคอมไพเลอร์โอเพนซอร์สด้วย เมื่อก่อนผมเคยคิดว่ามีแต่คอมไพเลอร์เชิงพาณิชย์แบบปิดทั้งหมด เลยไม่เคยสนใจ Ada เลย ตอนนี้คงต้องกลับไปดูอีกครั้ง
    • คอมไพเลอร์ GNAT เปิดตัวมานานกว่า 30 ปีแล้ว และครั้งหนึ่งเคยมีความเข้าใจผิดว่าเพราะไม่มี GPL runtime exception ทำให้ผลลัพธ์ที่คอมไพล์ได้ต้องเป็น GPL ไปด้วย แต่ตอนนี้ประเด็นนั้นได้รับการแก้ไขแล้ว
    • GNAT ถูกสร้างบนพื้นฐานของ GCC มาตั้งแต่ยุค 90 และในบางมหาวิทยาลัยก็เคยนำ GNAT ไปใช้โดยตรงในวิชาที่เน้นการปฏิบัติ เช่น real-time programming ผมเองก็เคยมีประสบการณ์ที่พยายามใช้ Ada เป็นภาษาเริ่มต้นสอนเขียนโปรแกรม ก่อนจะเปลี่ยนไปใช้ Pascal และ C++ ในเวลาต่อมาอย่างรวดเร็ว
  • ในวงการ 3D printing โปรเจกต์หนึ่งที่ผมสนใจเมื่อไม่นานมานี้คือบอร์ดควบคุมเครื่องพิมพ์และเฟิร์มแวร์ชื่อ Prunt พัฒนาเฟิร์มแวร์ด้วย Ada ซึ่งเป็นตัวเลือกที่ค่อนข้างแปลกใหม่แต่ก็เข้ากันในเชิงแนวคิดได้ดี
    เว็บไซต์ Prunt
    Prunt GitHub
  • ตอนท้ายของ Case Study 2 มีประโยคว่า “ถ้าไคลเอนต์ต้องรู้จัก SIDE_LENGTH ให้เพิ่มฟังก์ชันที่คืนค่านี้” แต่จริง ๆ ไม่จำเป็นต้องใช้ฟังก์ชันก็ได้ การประกาศค่าคงที่แบบ pub const SIDE_LENGTH: usize = ROW_LENGTH; ตรงไปตรงมากว่า
  • ผมไม่เห็นด้วยกับข้ออ้างที่ว่าทั้งสองภาษาสนับสนุนการเขียนโปรแกรมแบบเน้นสแตกเหมือนกัน Ada กลับสนับสนุนแนวทางการจัดสรรแบบสถิติค่อนข้างชัดเจนกว่า
  • รู้สึกแปลกใจที่มีการนำเสนอว่าการที่ดัชนีของอาร์เรย์ใน Ada เป็นชนิดใดก็ได้เป็นข้อดีอย่างมาก เพราะแทบทุกภาษามี dictionary (hash map) อยู่ใน standard library อยู่แล้ว และ Rust ก็มีให้ถึงสองแบบ
    • ที่พูดถึงกันตรงนี้คืออาร์เรย์ที่เป็น built-in ของภาษา เช่น ใน Ada ถ้ากำหนดให้ดัชนีของอาร์เรย์ eggs เป็นชนิด BirdSpecies ก็จะเขียน eggs[Robin], eggs[Seagull] ได้อย่างมีความหมาย แต่ eggs[5] จะไม่ถูกอนุญาต ใน Rust ก็สร้างโครงสร้างข้อมูลตามต้องการได้เหมือนกัน (เช่น implement Index<BirdSpecies>) และทำให้ eggs[Robin] ใช้ได้ แต่ eggs[5] เป็น error ต่างกันตรงที่ Rust ยังไม่ได้รองรับสิ่งนี้ในฐานะ “อาร์เรย์” ของภาษาตรง ๆ และเมื่อ Ada อนุญาตให้ “ชนิดที่ผู้ใช้กำหนดเองประกาศเป็นจำนวนเต็มที่เป็นบางส่วนย่อยของช่วงได้” การ indexing แบบนี้จะยิ่งแสดงพลังชัดเจน ใน Rust ตอนนี้ยังสร้าง range-limited integer แบบผู้ใช้กำหนดเองล้วน ๆ ไม่ได้ (มีแค่แบบภายในอย่าง NonZeroI16 เป็นต้น) ถ้า Rust รองรับถึงระดับนี้ได้จริงจะดีมาก
    • Ada ก็มี hash map และ set ในมาตรฐานเหมือนกัน ดูได้ที่ มาตรฐานเกี่ยวกับ Ada containers (ดูหัวข้อ A.18) จุดเด่นของการใช้งานชนิดดัชนีอาร์เรย์ที่เป็นช่วง “ค่าต่อเนื่อง” ทั่วไป (เช่น 0~N-1) คือในกรณีของ dense map หรืองานที่ต้องเข้าถึงหน่วยความจำต่อเนื่อง ประสิทธิภาพจะดีกว่า dictionary มากและยังเป็นมิตรกับ cache ด้วย
    • การจำกัดชนิดดัชนีอาร์เรย์ (subtype) ใน Ada เป็นแนวคิดที่ต่างจาก dictionary โดยโครงสร้างอย่างสิ้นเชิง เพราะภาษาสามารถจำกัดได้ถึงระดับว่าอนุญาตให้ดัชนีมีค่าแบบใดบ้างในตัวภาษาเอง