10 คะแนน โดย GN⁺ 2024-12-29 | 3 ความคิดเห็น | แชร์ทาง WhatsApp

#9512 - Rewrite It in Rust

  • เชลล์ Fish ถูกเขียนใหม่ด้วย Rust โดยไม่มีโค้ด C++ เหลืออยู่เลย และประกอบด้วย Rust แบบเพียวเกือบ 100%
  • มีการเปิด PR (#9512) เพื่อย้าย Fish จาก C++ ไปเป็น Rust ตั้งแต่ราว 2 ปีก่อน
  • แม้ว่า Fish จะเคยย้ายจาก C ไป C++ มาก่อน แต่การย้ายมาเป็น Rust เป็นโครงการที่ใหญ่กว่ามาก

ปัญหาใน C++

  • ความต่างของเครื่องมือและคอมไพเลอร์: เครื่องมือของ C++ ไม่ค่อยดีนัก และการรองรับมาตรฐาน C++ รุ่นใหม่ทำให้ผู้แพ็กเกจและผู้ร่วมพัฒนาต้องรับความซับซ้อนเพิ่มขึ้น
  • ความปลอดภัยของเธรด: การรันคำสั่งภายในของ Fish ปัจจุบันยังเป็นแบบลำดับต่อเนื่อง และหากต้องการเพิ่มพรอมป์ต์แบบอะซิงก์หรือระบบเติมคำสั่งแบบไม่บล็อก ก็จำเป็นต้องรองรับการประมวลผลแบบขนาน
  • ความซับซ้อนของภาษา: header file, template และการจัดการสตริงของ C++ มีความซับซ้อนและไม่ปลอดภัย
  • ชุมชน: C++ ไม่สามารถดึงดูดผู้ร่วมพัฒนาได้มากนัก
  • ปัญหาเรื่อง dependency: มีความยุ่งยากจากความไม่เสถียรและปัญหาการบิลด์ของไลบรารี C บางตัว (curses)

เหตุผลที่เลือก Rust

  • ความสนุกและน่าสนใจ: Fish เป็นโปรเจกต์งานอดิเรก จึงต้องการภาษาที่สนุกและน่าสนใจ และ Rust ก็มีเสน่ห์ต่อผู้ร่วมพัฒนามากกว่า
  • เครื่องมือที่ยอดเยี่ยม: ติดตั้งคอมไพเลอร์ได้ง่ายด้วย rustup และข้อความแจ้งข้อผิดพลาดก็ชัดเจน
  • Ergonomics: มีระบบ use ที่ชัดเจน และมีฟีเจอร์ที่ปลอดภัยอย่าง Option และ Result
  • การออกแบบภาษาที่ดี: ระบบ pointer และ option ของ Rust ปลอดภัยกว่า C++ มาก
  • รองรับการประมวลผลแบบขนาน: Send และ Sync ของ Rust ทำให้การประมวลผลแบบขนานที่ปลอดภัยเป็นไปได้
  • การจัดการ dependency: สามารถเพิ่มการรองรับฟอร์แมตภายนอกอย่าง YAML, JSON เป็นต้น ได้อย่างง่ายดาย

การรองรับแพลตฟอร์ม

  • รองรับแพลตฟอร์มหลักส่วนใหญ่ เช่น macOS, Linux, BSD และอื่น ๆ โดยไม่ได้ตั้งเป้ารองรับ Windows แบบเนทีฟ
  • Fish เป็นเชลล์ที่เน้น UNIX เป็นหลัก จึงโฟกัสที่ UNIX API และภาษาสคริปต์มากกว่าสภาพแวดล้อม Windows

กระบวนการพอร์ต

  • Fish ย้ายจาก C++ ไป Rust แบบค่อยเป็นค่อยไปตามแนวคิด “ปลาแห่งเธซีอุส” โดยย้ายคอมโพเนนต์ทีละตัวและจัดให้ C++ กับ Rust อยู่ร่วมกันได้
    • เรือของเธซีอุส (Ship of Theseus): “ถ้าเปลี่ยนไม้กระดานทุกแผ่นของเรือลำหนึ่งเป็นของใหม่ทั้งหมด มันยังเป็นเรือลำเดิมอยู่หรือไม่?”
  • ใช้ FFI: ใช้ autocxx เพื่อสร้าง binding ระหว่าง C++ และ Rust แล้วพอร์ตทีละคอมโพเนนต์
  • พอร์ตครั้งใหญ่: บางส่วนเฉพาะทาง (เช่น การจัดการ I/O) ถูกย้ายแบบแยกเดี่ยวเพื่อลดโค้ด FFI ที่ซับซ้อน
  • ปรับปรุงเครื่องมือ: ในระหว่างการพอร์ต มีการปรับแต่ง autocxx เพื่อแก้ปัญหาการทำงานร่วมกันระหว่าง Rust กับ C++

ไทม์ไลน์

  • มกราคม 2023: เปิด PR แรก
  • มกราคม 2024: ลบโค้ด C++ ออกทั้งหมด
  • ธันวาคม 2024: ออกรุ่นเบตา Fish 4.0

จุดที่ติดขัดกับ Rust

  • ปัญหาด้าน portability: แนวทาง #[cfg(...)] ของ Rust ไม่มีประสิทธิภาพนักเมื่อต้องจัดการความแตกต่างของระบบในระดับล่าง
  • การแปลภาษา: format string ของ Rust ถูกตรวจสอบตอนคอมไพล์ แต่ไม่เอื้อต่อการแปล
  • เวลาบิลด์: การใช้ LTO และการบิลด์แบบ release ค่าเริ่มต้นอาจทำให้เวลาบิลด์นาน
  • ระหว่างการพอร์ตมีข้อผิดพลาดอยู่บ้าง แต่ส่วนใหญ่แก้ได้ไม่ยาก

ผลลัพธ์สำคัญ

  • ถอด curses ออก: แทนที่ฐานข้อมูล terminfo ด้วย Rust crate เพื่อแก้ปัญหา global state และปัญหาการบิลด์
  • ไฟล์ปฏิบัติการเดี่ยว: สามารถสร้างไบนารี Fish ที่รวม dependency ทั้งหมดไว้ภายในได้
    • ทำให้แพ็กเกจ Fish ติดตั้งได้ด้วยตัวเอง ผู้ใช้จึงใช้งานได้สะดวกขึ้น
  • ประสิทธิภาพดีขึ้น: ปรับการใช้หน่วยความจำให้เหมาะสมขึ้น และเพิ่มฟีเจอร์ใหม่ได้ง่ายขึ้น

ข้อจำกัด

  • ยังไม่สามารถเอา CMake ออกได้ทั้งหมด
  • ยุติการรองรับ Cygwin: เพราะไม่มี Rust target
  • บน Windows ยังรันได้ผ่าน WSL เท่านั้น

ปัจจุบันและอนาคต

  • Fish 4.0 พอร์ตเสร็จสมบูรณ์แล้วและมีประสิทธิภาพดีขึ้น
  • Fish ยังเป็น UNIX shell เช่นเดิม แต่การย้ายไป Rust ทำให้เพิ่มฟีเจอร์ใหม่ได้มากขึ้น
  • ตอนนี้มีโค้ดเบสที่ย้ายมาเป็น Rust อย่างสมบูรณ์แล้ว ทำให้ดูแลรักษาและเพิ่มฟีเจอร์ได้ง่ายกว่าเดิม และสามารถใช้ข้อดีของ Rust เพื่อเพิ่มความสามารถใหม่ ๆ ได้
  • การย้ายครั้งนี้เสร็จสมบูรณ์อย่างประสบความสำเร็จ และส่งผลในทางบวกทั้งต่อผู้ร่วมพัฒนาและผู้ใช้

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

 
annyeong 2024-12-30

ผมอิจฉาความใช้งานง่ายของ fish แต่เพราะปัญหาเรื่องความเข้ากันได้ ประสิทธิภาพ ฯลฯ เลยตั้งค่า zsh ให้คล้าย fish มากที่สุดแล้วใช้งานอยู่ ตอนนี้เลยตั้งตารอดูว่า fish ที่เปลี่ยนไปจะเป็นยังไง 👀

 
GN⁺ 2024-12-29
ความคิดเห็นบน Hacker News
  • ขอแสดงความยินดีกับทีม Fish และรายละเอียดของโปรเจ็กต์ก็น่าสนใจ สงสัยว่านี่อาจเป็นโปรเจ็กต์ที่ใหญ่ที่สุดที่ย้ายจาก C++ ไปเป็น Rust อย่างสมบูรณ์หรือไม่ ซึ่งอาจเป็นบทเรียนที่มีประโยชน์ต่อโปรเจ็กต์อื่น

    • Fish ไม่ได้ออกเป็นโปรแกรมแบบไฮบริดระหว่าง C++ กับ Rust เพราะขั้นตอนการทดสอบขั้นสุดท้ายยังไม่เสร็จสมบูรณ์
    • มีคนที่ไม่เข้าใจแรงจูงใจในการเพิ่มความสามารถของ C++ เข้าไปใน Rust แต่เรื่องนี้อาจเป็นกรณีศึกษาที่ดีได้
    • มีความเห็นว่าน่าจะดีถ้าสามารถเขียนโค้ด Rust ใหม่ลงในโค้ดเบส C++ ได้
  • ข้อบ่นหลักเกี่ยวกับ Rust คือการรองรับการตรวจจับเวอร์ชัน โดยการตรวจจับความสามารถเหมาะกว่าทั้งกับดิสโทร เว็บเบราว์เซอร์ และคอมไพเลอร์

    • การตรวจจับเวอร์ชัน/ชื่อคือเหตุผลที่ Chrome และ IE แกล้งทำเป็น Mozilla และที่ Clang แกล้งทำเป็น GCC ขณะที่การตรวจจับความสามารถไม่ก่อให้เกิดปัญหาแบบนี้
  • หนึ่งในเป้าหมายของการพอร์ตคือการเอา CMake ออก แต่ไม่สำเร็จ Cargo ยอดเยี่ยมสำหรับการบิลด์ แต่เรียบง่ายเกินไปสำหรับการติดตั้ง Fish มีทั้งสคริปต์และเอกสารจำนวนมาก จึงไม่เข้ากับกรณีใช้งานของ Cargo

    • อยากให้มีเครื่องมืออื่นมารองรับกรณีใช้งานนี้มากกว่าที่จะขยาย Cargo ให้ครอบคลุม
  • เมื่อหลายปีก่อนเคยย้ายจาก bash ไป zsh แล้วก็พอใจ แต่พอลองใช้ fish บนคอมพิวเตอร์เครื่องใหม่กลับรู้สึกว่า zsh ทั้งยุ่งยากและล้าสมัย แนะนำให้ลองใช้ fish สักสองสามสัปดาห์

  • น่าเสียดายที่ไม่รองรับ Cygwin และหวังว่า Rust จะรองรับ Cygwin เป็นเป้าหมายการบิลด์

  • ประทับใจกับความพยายามของทีม Fish และรอดูว่าโปรเจ็กต์จะพัฒนาต่อไปอย่างไร

  • สงสัยว่าผู้แพ็กเกจของดิสโทรจะสามารถแพ็กเกจ Rust-fish ตามแนวทางของ Debian ได้สะดวกแค่ไหน

  • ขอแสดงความยินดีกับทีม Fish และคิดว่าเชลล์ที่ดีที่สุดยิ่งดีขึ้นไปอีก พร้อมเสนอให้อัปเดตแท็กไลน์ของโปรเจ็กต์เป็น "Finally, a shell for the 00s!"

  • หลังจากย้ายจาก zsh มา Fish การตั้งค่าง่ายขึ้นมาก และ Fish ก็ทำงานตรงตามที่คาดหวัง จึงไม่คิดจะเปลี่ยนกลับอีก

  • มาโคร cfg! จะถูกคอมไพล์เป็น true/false ดังนั้นโค้ดภายใน if guard จึงต้องสามารถคอมไพล์ได้ และอาจล้มเหลวได้หากคอมไพล์โดยไม่มี my_feature

  • Fish ใช้เธรดสำหรับการเติมคำสั่งอัตโนมัติและการเน้นไวยากรณ์ และยังมีโปรเจ็กต์ระยะยาวเพื่อเพิ่มความสามารถด้าน concurrency ให้กับภาษา