36 คะแนน โดย GN⁺ 2025-08-23 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • Rust เป็นภาษาแบบ แนวคิดหลากหลายส่วนถักทอกันอย่างแน่นแฟ้น ทำให้แม้แต่การเข้าใจโปรแกรมพื้นฐานก็ต้องเรียนรู้หลายองค์ประกอบไปพร้อมกัน
  • ฟังก์ชัน, เจเนอริก, enum, pattern matching, trait, reference, ownership, Send/Sync, Iterator ฯลฯ ล้วนเป็น องค์ประกอบแกนหลักที่ถูกออกแบบให้ทำงานร่วมกัน
  • เมื่อเทียบกับ JavaScript แล้ว JS สามารถเขียนโค้ดได้แม้รู้เพียงบางแนวคิด แต่ Rust นั้น ต้องเข้าใจบริบทของภาษาทั้งระบบก่อน จึงจะเขียนโค้ดที่มีความหมายได้
  • ความซับซ้อนลักษณะนี้ของ Rust แม้จะเพิ่มกำแพงในการเรียนรู้ แต่ก็ให้ทั้ง ความปลอดภัยและความสม่ำเสมอ และส่งผลอย่างมากต่อวิธีออกแบบโค้ด
  • โครงสร้างทางภาษาที่ร้อยเรียงกันเช่นนี้ทำให้ Rust มีความพิเศษ และวิสัยทัศน์ของ “Rust ที่เล็กลง” ก็ชวนให้กลับมาทบทวน ปรัชญาภาษาที่เชื่อมประสานกันอย่างประณีต

ความยากในการเรียนรู้ Rust

  • แม้ Rust จะมีอุปสรรคในการเริ่มต้นสูง แต่ก็มีผู้คนจำนวนมากร่วมกันพัฒนา เอกสาร, API และการวินิจฉัยข้อผิดพลาด มาโดยตลอด
  • แนวคิดพื้นฐานได้แก่ ฟังก์ชันแบบ first-class, enum, pattern matching, เจเนอริก, trait, reference, borrow checker, ความปลอดภัยด้านการทำงานพร้อมกัน, iterator เป็นต้น
  • แนวคิดเหล่านี้ พึ่งพาและพันเกี่ยวกัน จนยากจะเรียนรู้แยกเป็นส่วน ๆ และไลบรารีมาตรฐานเองก็ใช้ความสามารถเหล่านี้เกือบทั้งหมด
  • ต่อให้เป็นโค้ด Rust ยาวเพียงราว 20 บรรทัด ก็ยังต้องเข้าใจหลายองค์ประกอบพร้อมกัน เช่นกระบวนทัศน์เชิงฟังก์ชัน, Result และการจัดการข้อผิดพลาด, ชนิดข้อมูลแบบเจเนอริก, enum, iterator เป็นต้น

เปรียบเทียบ Rust กับ JavaScript

  • เมื่อเขียนโปรแกรมตรวจจับการเปลี่ยนแปลงไฟล์แบบเดียวกันด้วย Rust และ JS จะเห็นว่า Rust มีแนวคิดทางภาษาจำนวนมากที่เชื่อมโยงกันอยู่
  • โดยพื้นฐานแล้ว JS สามารถเขียนโค้ดที่ทำงานได้ หากเข้าใจเพียง ฟังก์ชันและการจัดการ null
  • นี่ไม่ได้หมายความว่า Rust แค่ยากกว่าเท่านั้น แต่แสดงให้เห็นว่า Rust เป็น ภาษาที่ออกแบบมาให้ต้องอาศัยความเข้าใจเชิงโครงสร้างของทั้งระบบภาษา

การออกแบบแบบเชื่อมโยงถึงกันของ Rust

  • แก่นของ Rust คือ การผสานกันของฟีเจอร์ที่ถูกออกแบบอย่างเป็นองค์รวม
    • enum จะใช้งานได้ไม่สะดวกหากไม่มี pattern matching และ pattern matching เองก็มีข้อจำกัดหากไม่มี enum
    • Result และ Iterator จะไม่สามารถถูกทำให้เกิดขึ้นได้เลยหากไม่มีเจเนอริก
    • แนวคิด Send/Sync และข้อจำกัดของ println จะถูกแสดงอย่างปลอดภัยไม่ได้หากไม่มี trait
    • borrow checker รับประกันความปลอดภัยของ Send/Sync ผ่านการวิเคราะห์การ capture ของ closure
  • การเชื่อมโยงถึงกันแบบนี้ทำให้ Rust ไม่ได้เป็นเพียงชุดของฟีเจอร์ แต่เป็นระบบภาษาที่บูรณาการกัน

วิสัยทัศน์ของ Rust ที่เล็กลง

  • ในปี 2019 without.boats ได้กล่าวถึง “Smaller Rust” พร้อมอภิปรายถึงความเป็นไปได้ของ Rust ที่เล็กและผ่านการขัดเกลา
  • ปัจจุบัน Rust เติบโตขึ้นมากแล้ว แต่แนวคิดของ Rust ที่เล็กลงยังคงช่วย เตือนให้เห็นแก่นแท้ของการออกแบบภาษาที่ประกบกันอย่างประณีต
  • เสน่ห์ของ Rust อยู่ที่องค์ประกอบทางภาษาซึ่งเป็นอิสระต่อกัน แต่เมื่อรวมเข้าด้วยกันแล้วกลับมอบทั้ง พลังในการแสดงออกและความปลอดภัย

บทสรุป

  • Rust เรียนรู้ได้ยาก แต่ ความสม่ำเสมอและความเป็นเนื้อเดียวกันของแนวคิดที่ถักทอกันอยู่ คือจุดแข็งสำคัญ
  • ด้วยโครงสร้างนี้ Rust จึงทำให้นักพัฒนาไม่ได้เพียงแค่เขียนโค้ด แต่ยังมี วิธีคิดที่คำนึงถึงทั้งความปลอดภัยและประสิทธิภาพไปพร้อมกัน
  • แก่นแท้ของ Rust อยู่ที่ “ภาษาหลักขนาดเล็กที่ประณีต” และนี่ก็ยังเป็นปรัชญาสำคัญแม้ใน Rust ที่ขยายตัวขึ้นในปัจจุบัน

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

 
GN⁺ 2025-08-23
ความเห็นจาก Hacker News
  • รู้สึกว่ามันช่างน่าขันที่แม้แต่โปรแกรม JS ที่ "เรียบง่าย" ก็ยังมีบั๊กอยู่ ในเอกสารของ fs.watch ระบุชัดว่าต้องตรวจสอบเสมอว่า filename ใน callback อาจเป็น null ได้ ถ้าเป็น Rust ข้อเท็จจริงนี้จะถูกสะท้อนอยู่ใน type system และบังคับให้จัดการ แต่ใน JS มันเขียนโค้ดแบบหยาบๆ ได้ง่าย เอกสารที่เกี่ยวข้อง
    • ถ้าใช้ Typescript จะถูกบังคับให้เช็ก null ด้วย เลยคิดว่านี่เป็นตัวอย่างที่ดีว่า TS เป็นขั้นกลางที่ภาระไม่มากนัก แต่ขยับเข้าใกล้ความถูกต้องแบบฝั่ง Rust มากขึ้นในโลก JS
    • ยังมีบั๊กเพิ่มอีก: for path in paths ต้องเป็น for (const path of paths) JS จะโยน error ทันทีถ้าไม่มีวงเล็บก็จริง แต่ความต่างระหว่าง in กับ of คือ in จะวนผ่าน index ของ iterable ไม่ใช่ค่าจริง ทำให้ index ถูกแปลงเป็น string แล้วหลุดเข้าไปเป็นอาร์กิวเมนต์ตัวแรกของ fs.watch ได้เลย และแม้แต่ TypeScript ก็อาจจับความผิดพลาดนี้ไม่ได้
    • อย่างที่ชี้ไว้ syntax ของลูปเองก็ไม่ถูกอยู่แล้ว ซึ่งแค่ลองรันก็น่าจะรู้ทันที ดังนั้นน่าจะมองได้ว่าผู้เขียนไม่ได้ใส่ใจกับโค้ด JS ชิ้นนั้นมาก และมันไม่ได้มีความหมายกับประเด็นหลักเท่าไร
    • ผมอาจมองข้ามไปเอง แต่อยากรู้ว่า kind มาจากไหน ใน console.log("${kind} ${filename}") มันควรเป็น eventType (string) มากกว่า kind
  • ขอทักเรื่องเล็กน้อยอย่างหนึ่ง println ของ Rust พิมพ์ได้เฉพาะ type ที่ implement trait Display หรือ Debug เท่านั้น เพราะงั้น Path จึงพิมพ์ตรงๆ ไม่ได้ ไม่ใช่ว่าทุก OS จะเก็บ path เป็น UTF-8 และ string type ของ Rust ก็เป็น UTF-8 ทั้งหมด นั่นแปลว่าการพิมพ์ Path อาจทำให้ข้อมูลสูญหายได้ Path จึงมีเมธอด display ที่คืน type ซึ่ง implement Display Rust ฝังเรื่องนี้ไว้ใน type system แต่ใน JS/TS มันยากที่จะระบุให้ชัดว่า string ภายในเป็น UTF-16 และ path ที่ไม่ใช่ Unicode ต้องใช้ TextEncoder/TextDecoder เองถึงจะจัดการได้ถูกต้อง จากประสบการณ์เก่าๆ ถ้าเซิร์ฟเวอร์ส่งข้อความมาเป็น Shift_JIS แล้วไปอ่านด้วย response.text() ใน runtime จะได้แค่ string ว่างๆ ถ้าไม่คุ้นกับปัญหา encoding ก็อาจเสียเวลา debug ไปหลายวันได้ และตัวอย่าง JS ก็มีทั้งบั๊กและ syntax error ที่ไม่มีในโค้ด Rust (ในลูปต้องใช้ for-of แทน for-in) จะบอกว่าตัวอย่างนี้ใช้แค่ "ฟังก์ชันชั้นหนึ่ง" อย่างเดียวก็คงไม่ใช่ เพราะยังต้องเข้าใจ iterator แบบ Rust ด้วย และยังใช้ CommonJS อีก นอกจากนี้ยังต้องเรียนรู้ async/await, Promises และ top-level await ด้วย โดย top-level await เพิ่งมีในบาง runtime รวมถึง node ไม่นานมานี้เอง และยังไม่มีใน JS engine บางตัว (เช่น Hermes ของ React Native)
    • นี่แหละเหตุผลที่ผมยังใช้ Rust ต่อไป ตัวอย่างนี้เป็นแค่กรณีหนึ่ง แต่ปัญหาเล็กๆ และกับดักแบบนี้มีอยู่เต็มไปหมดในภาษาอื่นๆ แต่ละอย่างอาจไม่เกิดขึ้นเสมอไป ทว่าพอรวมกันตลอดอายุของโปรแกรม ก็จะมีบั๊กประหลาดโผล่มาเรื่อยๆ จากที่ไหนไม่รู้และต้องคอยตามหาอยู่ตลอด ใน Rust เรื่องแบบนี้ไม่เกิดขึ้น type system ช่วยกันกรณีไร้สาระได้ล่วงหน้าเป็นจำนวนมหาศาล จริงๆ แล้วพอปล่อยซอฟต์แวร์ที่เขียนฟีเจอร์ครบด้วย Rust ออกไป ผมก็มีแค่เพิ่มฟีเจอร์เป็นครั้งคราว และแทบไม่ต้องเหนื่อยกับการไล่บั๊กทั่วไปอีกเลย แน่นอนว่าบั๊กเชิงตรรกะเกิดได้ทุกที่ แต่ปัญหาจากความไม่ตรงกันของ type/โครงสร้างแบบโง่ๆ ที่เจอบ่อยในภาษาอื่นถูกตัดทิ้งไปตั้งแต่ต้น ทำให้ productivity และการดูแลรักษาเป็นคนละประสบการณ์เลย

    • ส่วนตัวรู้สึกว่าใน JS/TS มีนักพัฒนาไม่มากที่เข้าใจ thenable/Promise กับ async-await แบบลึกจริงๆ เคยเห็นอะไรแบบนี้ด้วย:

      var fn = async (param) => new Promise((res, rej) => {
        fooLibraryCall(param).then(res).catch(rej);
      });
      

      คือเอา wrapper แบบ callback ไปห่อเป็น Promise แล้วก็เอากลับมาใช้ใน async function อีกที เห็นแบบนี้ทีไรปวดใจมาก และเจอโค้ดลักษณะนี้ตามที่ต่างๆ จริงๆ ยิ่งถ้าคิดถึงการ import โมดูล, async import(), transpile, code splitting ฯลฯ ก็ยิ่งซับซ้อนจริงๆ

  • คิดว่าคำพูดของ Bjarne จริงๆ แล้วเป็น sales pitch สำหรับใช้แก้ตัวซ้ำๆ ให้กับการที่ C++ แย่ลงเรื่อยๆ ช่วงแรกอาจจริงใจ แต่ตอนนี้มันเหมือน pattern ซ้ำๆ โครงสร้างเป็นแบบนี้:
    1. "มีภาษาที่เล็กและสะอาดกว่าซ่อนอยู่ใน C++"
    2. แต่เราแยกภาษาออกมาเป็น subset ไม่ได้ เลยบอกว่าขอทำ superset (เพิ่มความสามารถ) ก่อน แล้วค่อยทำ subset ทีหลัง
    3. superset นั้นก็เข้าไปอยู่ใน C++N+1 แล้วการคุยเรื่อง subset จริงๆ ก็ถูกเลื่อนไปทีหลังและวนซ้ำ
    4. C++N+1 ก็ยิ่งซับซ้อนขึ้น และแบบนี้ก็วนไปไม่จบ คนที่เห็นสิ่งนี้ซ้ำๆ คงไม่เข้าใจว่าทำไมคนอื่นยังอยู่ต่อ สุดท้ายแล้ว "ภาษาที่เล็กและสะอาดกว่า" ก็ไม่เคยเกิดขึ้น มีแต่ทำขั้นแรกซ้ำไปซ้ำมา
    • มันทำให้นึกถึง xkcd 927 xkcd 927 มาตรฐาน C++ แต่ละรอบยิ่งซับซ้อนขึ้น แม้จะมีการเปลี่ยนแปลงที่ดี แต่ก็มักเข้ากันได้ไม่ดีกับเวอร์ชันเก่า และ source code ก็ยิ่งเละขึ้นเรื่อยๆ ผมดูแล OSS library อยู่สองตัว แต่ตอนนี้แทบไม่ได้ใช้แล้ว และช่วงนี้ก็กำลังคิดว่าจะทนไปได้อีกนานแค่ไหน Rust นี่สดชื่นมากหลังย้ายมาจาก c++11/14/17/20 แต่ถ้าไม่รู้ทั้งหมด Rust เองก็ใหญ่พอสมควรเหมือนกัน เลยรู้สึกว่าสิ่งที่บทความนี้ชี้นั้นตรงประเด็นมาก
  • ไม่มีใครเสียสมาธิทันทีที่เห็น shebang (สคริปต์ rust ที่รันได้เอง) เหรอ? ผมตกใจเหมือนตอนเคยเจอแบบเดียวกันใน Go เมื่อก่อน ดูมีประโยชน์มากและน่าจะพอใช้กับงานพื้นฐานได้จริง เคยเห็นอะไรคล้ายกันในโปรเจกต์ที่ใช้ rust จัดการ build/test pipeline ด้วย น่าจะเป็นทางเลือกที่ดีทีเดียวสำหรับงานแบบนี้ แต่โดยทั่วไป ถ้าผมต้องเขียนสคริปต์ที่เกิน bash ไปนิดหน่อย ผมจะใช้ Deno+TS ผมอยู่กับ JS มานานที่สุด (28 ปี) รองลงมาคือ C# 24 ปี ใช้ Node มาตั้งแต่ยุคแรกๆ และ Deno ดูแลง่ายกว่า Node หรือ Python ในแง่การแชร์/รวมศูนย์แพ็กเกจ ส่วน cargo frontmatter ก็ทำงานคล้ายกัน
    • ผมเป็นคนที่ออกแบบ/ลงมือทำการรวม script เข้ากับ cargo เอง (ก่อนหน้านี้ก็มี third-party implementation อยู่หลายตัว) ดีใจมากที่เห็นคนเอาไปใช้จริงและดีใจที่มีการพูดถึงมันด้วย ดูเอกสารได้ มีการถกกันอยู่นานมากว่าแบบไหนถึงจะเหมาะ จะผูกกับภาษายังไง และจะกำหนดขอบเขตของรีลีสแรกไว้แค่ไหน ตอนนี้กำลังเก็บงานส่วนท้ายๆ เช่น style guide และอัปเดต Rust reference ส่วนงานใหญ่ที่เหลือคือรายละเอียดเกี่ยวกับ rustfmt, rust-analyzer, bug fix ใน rustc และการปรับปรุง error reporting ของ Cargo ผมเองก็เขียนสคริปต์สำหรับ reproduce issue ด้วย cargo script ทุกวัน
    • จริงๆ ผมเสียสมาธิจากการเริ่มค้นคีย์เวิร์ดฟีเจอร์ -Zscript แล้วไปไล่อ่านต่อ มันทำมาตั้งแต่ปี 2023 และมี open issue ที่ดูใกล้เสร็จมากแล้วด้วย ผมยังเห็นใน repo ของ ZomboDB ว่าใช้ rust จัดการ build pipeline เช่นกัน แต่ยังไม่ได้เข้าใจบริบททั้งหมด อยากบอกด้วยว่า cargo frontmatter มีประโยชน์มากในแง่ portability ของสคริปต์ แค่แชร์ไฟล์เดียวก็พอ และสามารถดึง dependency มาใช้ได้ทันทีโดยไม่ต้องติดตั้ง/initialization เพิ่มแบบ Python หรือ Node.js
    • เห็นมีคนบอกว่า Go ก็ทำแบบเดียวกันได้ เลยสงสัยว่าช่วยอธิบายเพิ่มได้ไหม ถ้าหมายถึงลิงก์นี้ ผมก็สนใจเหมือนกัน
    • ถึงผมจะใช้ JS และ C# มานาน แต่จะเลือกระบบในปี 2025 ด้วยเหตุผลแบบนั้นก็คงไม่ใช่ เพราะตลอด 20 ปีที่ผ่านมาอะไรๆ ดีขึ้นมากแล้วจริงๆ
    • มันก็เป็นแค่ความสามารถพื้นฐานของ Unix เท่านั้นเอง ไฟล์ที่ขึ้นต้นด้วย #!/some/path เชลล์ก็แค่ส่งทั้งไฟล์เข้า stdin ของคำสั่งที่ระบุแล้วรัน
  • ผมสงสัยว่าคำว่า "มีภาษาที่เล็กและสะอาดกว่ากำลังโผล่ออกมาจากข้างใน Rust" ใน Rust นั้นหมายถึงภาษาไหนกันแน่ อ่านจากบทความเหมือนยังต้องมี reference, lifetime, trait, enum ฯลฯ ครบอยู่ดีถึงจะทำงานได้ ซึ่งก็แทบไม่ต่างจาก Rust เท่าไร ตอนท้ายมีคำใบ้สองอย่างคือ "Rust ที่ผมอยากใช้" กับ "Rust ในอดีต" แต่ก็ยังไม่ค่อยชัด ผมไปอ่าน "Notes on a smaller Rust" ของ withoutboats ด้วย แต่เป้าหมายการออกแบบมันต่างจาก Rust เอง คือไม่ได้พยายามจะเป็น Rust แต่เป็นการหยิบบทเรียนจาก Rust มาใช้เวลาออกแบบภาษาใหม่มากกว่า เป็นตัวอย่างของภาษาที่ตอบโจทย์ "เมนสตรีม" (เช่น GC, การคอมไพล์/ไวยากรณ์ที่ง่ายขึ้น) มากกว่า ไม่ใช่ภาษาที่อยากเป็น Rust ประเด็นที่สองคือมีการบอกว่า "ภาษาที่ผมตกหลุมรักตอนเริ่มเรียนในปี 2018 ก็คือ Rust ที่เล็กกว่าอันนั้น" แต่จริงๆ แล้วหลังปี 2018 Rust ก็ไม่ได้เปลี่ยนไปมากในเชิงแก่นสาร สิ่งที่เปลี่ยนส่วนใหญ่คือความยืดหยุ่นทางไวยากรณ์อย่าง edition ส่วนข้อยกเว้นใหญ่จริงๆ มีแค่ async กับ const ถ้างั้นก็บอกตรงๆ ไปเลยว่า "Rust ก่อนมี async กับ const เล็กและสะอาดกว่า" จะชัดกว่า แต่ในบทความไม่ได้อธิบายตรงขนาดนั้น ซึ่งน่าเสียดาย
    • ถ้าจะพูดถึง 'Rust ที่เล็กและสะอาดกว่า' ภาษา Austral ก็เป็นตัวอย่างที่นึกออก
    • มีคนแย้งว่าภาษาที่ง่ายกว่า (เล็กกว่า) แต่ยังเก็บแนวคิดแกนกลางของ Rust เอาไว้ก็เป็นไปได้ เช่น ถ้าตัดพวก Copy trait, reborrowing, deref coercion, การ into_iter อัตโนมัติในลูป, การเรียก drop อัตโนมัติเมื่อออกจาก scope (จะให้เรียกเองหรือให้คอมไพเลอร์ error แทนก็ได้), ค่าเริ่มต้น :Sized ใน trait bound, lifetime elision, match ergonomic และตัวช่วยอัตโนมัติ/ความสะดวกอื่นๆ ออกไป ก็จะได้ Rust ที่ง่ายแบบเชิงกลไกจริงๆ แต่ภาษานั้นจะใช้งานในชีวิตประจำวันได้อึดอัดมาก และก็น่าขำที่สิ่งเหล่านี้จริงๆ ออกแบบมาเพื่อช่วยมือใหม่
    • ผมอ่านอย่างละเอียดมาก และจริงๆ ความตั้งใจของผมก็คือจะบอกว่า Rust ก่อนมี async และ const นั้นเล็กและสะอาดกว่า เหตุผลที่ไม่พูดตรงๆ เพราะมีเพื่อนหลายคนที่ทำงานพัฒนาฟีเจอร์เหล่านั้น Matklad อธิบายไว้ดีมากใน lobste.rs ว่า Rust ปี 2015 มีความสำเร็จรูปและความสอดคล้องกันมากกว่า แต่ vision ของ Rust ไม่ใช่ความสอดคล้องสมบูรณ์แบบ (coherence) หากเป็นการเป็นภาษาที่ใช้งานได้จริงในภาคอุตสาหกรรม
  • ผมอาจมีอคติ แต่คิดว่า Rust เป็นภาษาที่ใกล้ความสมบูรณ์แบบที่สุด borrow checker น่ารำคาญก็จริงแต่จำเป็นมาก ถ้าเป็นโค้ดที่มีบั๊กแบบเดียวกันใน C มันคงพังตอน runtime ไปแล้ว ซึ่งสุดท้ายก็ต้องแก้บั๊กอยู่ดี ความต่างคือ Rust บังคับให้แก้ก่อนคอมไพล์ ส่วน C จะทำให้คุณต้องไปกู้สถานการณ์ตอนดึกๆ ผมไม่ได้คิดว่า Rust ยาก แต่คิดว่ามันต้องเปลี่ยนวิธีคิด เป็นการเปลี่ยนพาราไดม์ไปสู่การเขียนโค้ดที่ปลอดภัยและมั่นคงกว่า การเปลี่ยนแปลงมักไม่สบายตัวอยู่แล้ว และนั่นน่าจะเป็นรากของแรงต้านต่อ Rust
    • Rust ยังห่างไกลจากคำว่าสมบูรณ์แบบ
      • ผมคิดว่าคอมไพเลอร์มีอิสระมากเกินไปในการตัดสินใจว่า deref จะถูกใช้เมื่อไรและในลำดับไหน .into() กับ trait From ก็ทำให้การแปลง type เกิดขึ้นแบบลับๆ เกินไป มาตรฐานไลบรารีเองก็มีฟังก์ชัน "อำนวยความสะดวก" แบบนี้เยอะ สุดท้าย type ของอ็อบเจ็กต์จึงคลุมเครือ และเชื่อมโยงการเรียกฟังก์ชันกับ implementation ได้ยากขึ้น (แน่นอนว่า IDE ช่วยได้บ้าง)
      • implicit return ทำให้ flow ของโปรแกรมพร่ามัวและชวนให้พลาด ตัวดำเนินการเครื่องหมายคำถามก็ไม่ใช่สิ่งที่ผมชอบนัก
      • Rust แยกโมดูลย่อยเล็กเกินไป จนถ้าจะทำอะไรที่มีประโยชน์ต้องพึ่ง dependency เป็นร้อยตัว แต่ละตัวก็ต้องดูแลและ vendor แยกกันถึงจะ build ได้เสถียร ซึ่งลำบากมาก
      • Async Rust ตอนนี้วุ่นวายสุดๆ
    • ไม่ใช่ว่าผมมีปัญหากับ borrow checker เอง แต่ประเด็นหลักคือ "ก้อน" ของ Rust โดยรวมมันใหญ่เกินไปแล้ว คนที่ชอบ Rust ดิบๆ ที่ยังไม่สมบูรณ์นักในปี 2018 (รวมผมด้วย) อาจไม่รู้สึกว่าตอนนี้มันน่าดึงดูดเท่าเดิม แน่นอนว่าถ้าเชี่ยวชาญแล้วมันทรงพลังมาก แต่ก็อดถามตัวเองไม่ได้ว่ามันคุ้มแรงขนาดนั้นหรือเปล่า ถ้าเป็นปี 2025 แล้วต้องเลือกทางเลือกแทน C/C++ ผมน่าจะเลือก Zig (ยกเว้นงาน Postgres เพราะ ecosystem ของ pgrx นั้นโดดเด่นจริงๆ) แต่ยังไงก็ยังดีกว่าทำงานกับ C
  • ผมคิดว่าไม่ควรแนะนำ Rust เป็นภาษาแรก การเรียนภาษาแรกเดิมก็ยากอยู่แล้ว แต่ Rust ทำให้แทบจะรันอะไรดูไม่ได้เลยจนกว่าโค้ดจะถูกต้องสมบูรณ์เพราะติด compiler error มันน่าท้อและทำให้คนเลิกง่ายกว่า แนะนำว่าเริ่มจาก Python, JavaScript หรือ Lua แล้วลองทำอะไรเร็วๆ อย่างเกมและวนลูปเรียนรู้จะดีกว่า
    • ประสบการณ์ผมต่างออกไป วิศวกร ML ที่บริษัทผมรู้แค่ Python แต่อยากมาช่วยใน codebase Rust ผมอธิบายพื้นฐานให้ประมาณชั่วโมงเดียว เขาก็ปรับตัวได้เร็วมากและ productive ขึ้นแทบจะทันที จริงๆ แล้วเวลาทำเกม ถ้าเอา string ไปส่งให้ฟังก์ชันที่ต้องการตัวเลขจนมัน crash คุณอาจเสียเวลามากกับการไล่หาสาเหตุ แต่ใน Rust คอมไพเลอร์จะบอกชัดเลยว่า "ตรงนี้เป็น string แต่ต้องเป็น int" เลยอาจ debug เสร็จเร็วกว่า แทนที่จะเสียทั้งวันกับ compiler error คุณก็ไม่ต้องเสียเป็นสัปดาห์กับ runtime error
    • ผมคือคนที่ถูกอ้างคำพูดไว้ด้านบนของบล็อก ผมสอน Rust เป็นภาษาแรกให้คนมาแล้วมากกว่า 400 คน เลยรู้สึกว่าข้อถกเถียงในเธรดนี้น่าสนใจมาก จากประสบการณ์ตรงยาวนาน ผมไม่ได้เห็นแค่ความเป็นไปได้ แต่ยังมีหลักฐานพอสมควรว่ามันใช้ได้ผลค่อนข้างดีด้วย
    • ผมยังไม่แน่ใจนัก แต่อยากเห็นครูที่เก่งจริงลองใช้ Rust เป็นภาษาแรก ตอนนี้รุ่นใหม่และมหาวิทยาลัยใช้ Python กันมาก แต่ในทางทฤษฎี Rust อาจยกระดับทั้ง cohort ได้ในฐานะภาษาแรกก็ได้ (แน่นอนว่าอาจมีปัญหาเชิงบริหารเพราะ fail rate สูงเกินไป หรือกลับกัน นักศึกษาที่เก่งอยู่แล้วอาจได้เรียนรู้มากขึ้น) บางอย่างที่เรียนจาก Rust เช่น move assignment หรือความหมายของคีย์เวิร์ด const อาจช่วยลดภาระในการต้องมาแก้นิสัยที่เรียนผิดมาจากภาษาเดิมในภายหลังด้วย
    • โดยทั่วไปผมมักจะแนะนำให้เลี่ยง static typing สำหรับภาษาแรก แม้ผมเองจะชอบ static typing แต่สำหรับมือใหม่มันมักเพิ่มความสับสนเปล่าๆ compiler error มักเป็นข้อความเชิงสมมุติฐานที่สวนทางกับความเข้าใจ และข้อความแนว "คอมไพเลอร์พิสูจน์ไม่ได้ว่านี่ไม่ใช่ none" อาจรู้สึกยากกว่าการเจอ runtime crash ใน test case แล้วหาตำแหน่งได้ตรงๆ มาก การค่อยๆ พิมพ์ค่าออกมาทีละบรรทัดเพื่อ troubleshoot มักแก้ได้เร็ว แต่ถ้าติดกับ compiler error ที่เข้าใจยากก็อาจหลงทางอยู่นานจริงๆ
    • Rust ไม่ได้เป็นภาษาที่แย่ ถ้าคุณสามารถรับทุกอย่างได้พร้อมกันในคราวเดียว ปัญหาคือไม่มีใครเรียนภาษาแบบนั้น และถ้ายังไม่เข้าใจแนวคิดหลักมากพอ คุณจะลองผิดลองถูกซ้ำๆ ใน Rust อยู่เรื่อยๆ สุดท้ายยังมีแนวคิดหลายอย่างที่ภาษาอื่นไม่สอนเลย ดังนั้นพอย้ายไปภาษาใหม่ก็อาจหงุดหงิดอีกรอบ
  • ตัวอย่างที่ใกล้เคียงที่สุดกับ "Rust แบบง่าย" ที่ผมเคยเห็นคือ Gleam. ดูเหมือนได้แรงบันดาลใจจาก Rust พอสมควร
    • การบอกว่า Gleam ได้แรงบันดาลใจจาก Rust เป็นความเข้าใจผิด ผู้สร้างไม่ได้พูดแบบนั้นอย่างเป็นทางการ คอมไพเลอร์เขียนด้วย rust ก็จริง แต่ Gleam มีพาราไดม์และ runtime เป้าหมายต่างออกไปมาก จึงไม่ใช่ตัวแทน Rust
    • ถ้าอยากได้อะไรแนว 'simple rust' อีกแบบ ก็แนะนำให้ดู fsharp ด้วย
    • หน้าแรกของ Gleam มีข้อความเรื่องสิทธิคนผิวดำ สิทธิคนข้ามเพศ และต่อต้านนาซี ทำให้ผมไม่สนใจภาษานี้เลย
    • สงสัยว่าใน Gleam จะทำ 3D ได้ไหม
  • สิ่งที่ทำให้ผมขัดใจคือมัน "ไม่อธิบายว่าโปรแกรม Rust นั้นทำอะไร" มีคำอธิบายเชิงเทคนิคยาวมาก แต่ไม่มีสรุปว่าโปรแกรมจริงๆ ทำอะไร ที่จริงมันก็แค่เฝ้าดูการเปลี่ยนแปลงของไฟล์แล้วพิมพ์ออกมาเท่านั้น ใน Rust งานง่ายๆ แค่นี้ยังต้องมี implementation ที่ซับซ้อน ซึ่งแสดงให้เห็นความยากของภาษาที่ต้องไปสนใจรายละเอียดภายในซึ่งไม่เกี่ยวกับปัญหาจริง ผมมองว่าความซับซ้อนนี้เป็นทั้งความท้าทายที่ต้องเผชิญ และเป็นกำแพงที่สร้างขึ้นเองด้วย
    • ภาษาอื่นก็มีปัญหาเดียวกัน แต่ Rust ช่วยให้คุณจัดการมันตั้งแต่เนิ่นๆ ไม่ใช่ทุกชื่อไฟล์จะพิมพ์ออกมาได้ และภาษาส่วนใหญ่ก็โยนภาระนี้ให้ผู้ใช้ Rust แสดง error/ความล้มเหลวให้ชัดผ่าน return type ส่วนภาษาอื่นต้องอาศัยกลไกอย่าง exception แทน แม้ภายนอกจะดูง่าย แต่ลึกๆ แล้วฝั่ง Rust อาจตรงไปตรงมามากกว่าก็ได้
    • implementation เองก็จริงๆ ง่ายมากเมื่อเทียบกับภาษา performance สูงอื่นๆ ทุกอย่างอยู่ในหน้าเดียว แบบนี้ยังไม่ง่ายพอจะเป็นตัวอย่างอีกหรือ?
    • คำอธิบายที่ง่าย ไม่ได้แปลว่า implementation จะง่ายเสมอไป XKCD 1425 อธิบายกรณีแบบนี้ไว้ดี (เช่น ตรวจว่ารูปถ่ายอยู่ในเขตอุทยานแห่งชาติไหมนั้นง่าย แต่จะบอกว่าเป็นรูปนกหรือไม่อาจต้องใช้ทีมวิจัย) xkcd 1425
  • ผมรู้สึกว่า Rust มีความสม่ำเสมอและเหนียวแน่นในเชิงความหมายค่อนข้างมาก เมื่อเทียบกับภาษาอื่นมีของประดับหรือ syntactic sugar น้อยกว่า เลยตรงไปตรงมามากกว่า interface ต่างๆ ก็มักเดินตามแพตเทิร์นของโมดูล mem ดังนั้นถ้าอยากเข้าใจโครงสร้างของ interface ให้ชัด แนะนำให้เริ่มจาก std::mem