1 คะแนน โดย GN⁺ 2025-08-16 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ทีม Ghostty ได้เขียน แอปพลิเคชัน GTK ขึ้นใหม่ทั้งหมด พร้อมใช้งาน ระบบชนิดข้อมูล GObject อย่างจริงจัง
  • ในกระบวนการนี้ การผสานรวมกับ ภาษา Zig และการตรวจสอบปัญหาหน่วยความจำด้วย Valgrind มีบทบาทสำคัญ
  • การนำระบบ GObject มาใช้ช่วยให้ การจัดการหน่วยความจำ และ การพัฒนาวิดเจ็ตแบบกำหนดเอง ง่ายขึ้นกว่าที่ผ่านมา
  • จากการใช้ Valgrind ทีมงานพบว่า ความปลอดภัยด้านหน่วยความจำ ของ Ghostty ดีขึ้นอย่างมาก
  • Ghostty GTK เวอร์ชันใหม่ได้กลายเป็นค่าเริ่มต้นสำหรับการบิลด์จากซอร์ส และมีกำหนดรวมอยู่ใน รีลีส 1.2

บทนำ

  • Ghostty เป็นเทอร์มินัลอีมูเลเตอร์ข้ามแพลตฟอร์มที่รองรับ macOS, Linux, FreeBSD
  • แต่ละแพลตฟอร์มมีจุดเด่นจากการใช้เนทีฟ GUI framework ของตนเอง
    • macOS: แอปขนาดใหญ่ที่พัฒนาด้วย Swift และ Xcode
    • Linux และ BSD: แอปพลิเคชันบน GTK ที่เชื่อมรวมกับ X11/Wayland โดยตรง
    • แกนกลางร่วมเขียนด้วย Zig และมี API ที่เข้ากันได้กับ C ABI
  • เหตุผลที่เขียนแอป GTK ขึ้นใหม่จากโครงสร้างเดิมสามารถดูได้จาก PR ต้นฉบับ
  • บทความนี้เน้นที่ การทำงานร่วมกับระบบชนิดข้อมูล GObject และ ประเด็นด้านหน่วยความจำที่ตรวจสอบด้วย Valgrind

ระบบชนิดข้อมูล GObject และ Zig

  • หากใช้ GTK โครงสร้างโดยพื้นฐานจำเป็นต้องทำงานร่วมกับ ระบบชนิดข้อมูล GObject
  • ในอดีตทีมพยายามหลีกเลี่ยงระบบ GObject และจัดการ วงจรชีวิตของอ็อบเจ็กต์ Zig ที่ไม่มีการนับอ้างอิงกับอ็อบเจ็กต์ GObject ด้วยตนเอง แต่พบปัญหาซ้ำ ๆ ว่าการคืนหน่วยความจำไม่สมบูรณ์
    • ตัวอย่าง: หน่วยความจำฝั่ง Zig ถูกคืนแล้ว แต่หน่วยความจำฝั่ง GTK ยังอยู่ หรือเกิดสถานการณ์ตรงกันข้ามซ้ำ ๆ
  • แนวทางนี้ไม่เพียงมีปัญหาเรื่องความถูกต้อง แต่ยังทำให้ใช้งาน ความสามารถเฉพาะของ GTK (event signal, property binding, action) ได้ยาก
  • ตัวอย่างที่ชัดเจนคือ เมื่อต้องรีโหลดโครงสร้างการตั้งค่า (config) องค์ประกอบ GUI ทั้งหมดที่เชื่อมอยู่ต้องอัปเดตอย่างสอดคล้องกัน ซึ่งกระบวนการนี้ซับซ้อนและเกิดข้อผิดพลาดบ่อย
    • ตอนนี้จัดการผ่าน GhosttyConfig GObject แบบนับอ้างอิงที่ห่อ Config struct ของ Zig และใช้การแจ้งเตือนการเปลี่ยนแปลงของ property เพื่อกระจายการเปลี่ยนแปลงไปทั่วทั้งแอปอย่างเป็นธรรมชาติ
  • การสร้างวิดเจ็ต GObject แบบกำหนดเองก็ง่ายขึ้น ทำให้สามารถใช้เทคโนโลยี UI สมัยใหม่ของ GTK เช่น Blueprint ได้
    • เมื่อไม่นานมานี้ การนำ Blueprint มาใช้ช่วยให้เพิ่มฟีเจอร์ใหม่อย่าง แท็บบน title bar ของ GTK และ ขอบกระดิ่งแบบเคลื่อนไหว ได้ง่ายขึ้น

Valgrind กับ GTK และ Zig

  • ตลอดกระบวนการพัฒนา มีการใช้ Valgrind เพื่อตรวจสอบปัญหาอย่างเป็นระบบ ทั้ง memory leak และการเข้าถึงหน่วยความจำที่ยังไม่ถูกกำหนด
  • การตรวจ Valgrind กับแอป GTK ทำได้ยาก และต้องใช้ ไฟล์ suppression จำนวนมาก (80% เป็นของ GTK เอง ที่เหลือเป็นไลบรารีภายนอกและไดรเวอร์ GPU)
  • การตรวจซ้ำอย่างต่อเนื่องทำให้สามารถค้นพบบั๊กหน่วยความจำซับซ้อนที่เกิดเฉพาะในบางกรณีได้ล่วงหน้า
    • ตัวอย่าง: หากไม่กำหนดค่าเริ่มต้นให้ GObject WeakRef อย่างถูกต้อง เมื่ออ็อบเจ็กต์เป้าหมายถูกคืนหน่วยความจำภายหลังจะเกิดการเข้าถึงหน่วยความจำที่ยังไม่ถูกกำหนด ซึ่ง Valgrind ตรวจพบได้ก่อน
  • จากประสบการณ์จริง ปัญหาภายใน โค้ดเบส Zig มีเพียง 2 กรณีเท่านั้น (leak 1 ครั้ง, การเข้าถึงที่ยังไม่ถูกกำหนด 1 ครั้ง) และทั้งสองก็เกิดขึ้นระหว่างการเชื่อมกับ 3rd party C API
    • ตัวจัดสรรหน่วยความจำสำหรับดีบักของ Zig และความสามารถในการผสานรวมกับ Valgrind ก็พิสูจน์แล้วว่าได้ผลจริง
  • ปัญหาหน่วยความจำอื่น ๆ ที่พบส่วนใหญ่เกิดจากขอบเขตของ C API และการจัดการวงจรชีวิตอันซับซ้อนของระบบ GObject
    • สรุปคือ หากต้องการใช้ C API ของไลบรารีที่ซับซ้อนอย่างปลอดภัย จำเป็นต้องมีเครื่องมืออย่าง Valgrind
  • ฟีเจอร์ช่วยด้านความปลอดภัยหน่วยความจำของ Zig ไม่ได้พิสูจน์ได้แค่ในเชิงทฤษฎี แต่ยังยืนยันได้จาก ประสบการณ์จริงในโครงการ

บทสรุป

  • นี่เป็นครั้งที่ ห้า ที่ผู้เขียนสร้างส่วน GUI ของ Ghostty ขึ้นใหม่ตั้งแต่ต้น
    • ตามลำดับคือ GLFW, macOS SwiftUI, macOS AppKit+SwiftUI, Linux GTK (เชิงกระบวนวิธี), Linux GTK+ระบบชนิดข้อมูล GObject
  • ในแต่ละรอบของการเขียนใหม่ ได้บทเรียนและการเติบโตทางเทคนิคใหม่ ๆ ทุกครั้ง
    • มีแผนจะนำบางส่วนของประสบการณ์ครั้งนี้ไปใช้กับโปรเจกต์ macOS ด้วย
  • ยังเน้นย้ำถึงความร่วมมืออย่างแข็งขันของทีมดูแลระบบ Ghostty GTK
  • แอปพลิเคชัน Ghostty GTK ที่เขียนขึ้นใหม่ได้กลายเป็นค่าเริ่มต้นสำหรับการบิลด์จากซอร์สแล้ว และจะถูกนำไปใช้ใน รีลีสทางการ 1.2

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

 
GN⁺ 2025-08-16
ความคิดเห็นจาก Hacker News
  • ผมไม่เคยทำงานกับ GTK โดยตรงมาก่อน แต่จากสิ่งที่คุณอธิบายมา มันให้ความรู้สึกคล้ายมากกับปัญหาที่เจอตอนทำ Godot binding ด้วย Zig มาก ๆ Godot มีแนวคิด OOP เยอะมาก ทั้งคลาส เมธอดเสมือน พร็อพเพอร์ตี ซิกแนล ฯลฯ และก็มี C API ที่รองรับแนวคิดทั้งหมดนี้ รวมถึงให้สร้างอ็อบเจ็กต์และคุณสมบัติแบบกำหนดเองได้ด้วย ต้องจัดการอายุการใช้งานของอ็อบเจ็กต์ในเอนจินเอง และยังมีโครงสร้างต้นไม้ของอ็อบเจ็กต์แบบ reference-counted อีก พอพยายามห่อปัญหาเรื่องอายุการใช้งานให้กลายเป็น API ที่เหมาะกับสำนวนของ Zig โดยเฉพาะ มันก็ซับซ้อนมาก เลยได้ทำ ไลบรารี oopz ขึ้นมาด้วย ตอนนี้สถานะ API ยังอยู่ประมาณนี้ และดูตัวอย่างจริงได้ที่นี่ ผมเองก็อยากลองทำ Ghostty frontend เป็น Godot extension เหมือนกัน

    • เมื่อก่อนผมเคยใช้ GTK binding ของภาษาต่าง ๆ โดยตรง แล้วจำได้ว่ามันไม่ค่อยสะดวก 98% ของมันโอเคดี แต่ 2% ที่เหลือจะมีพวกกรณีแบบ “ฟังก์ชันนี้รับ ownership ของ reference ของอ็อบเจ็กต์หรือไม่ ขึ้นอยู่กับอาร์กิวเมนต์ตัวอื่น” อะไรทำนองนี้ ซึ่งทำให้การวิเคราะห์วงจรชีวิตของอ็อบเจ็กต์ปวดหัวมาก
    • ขอบคุณมาก และขอเสริมว่าตอนพยายามเขียนโค้ด Godot ใน C# ให้มีประสิทธิภาพดี ผมเคยเจอปัญหาที่ต้องแปลงไปมาระหว่างประเภทของเอนจินบ่อยมาก จนเกิด allocation ซ้ำ ๆ ตลอด เลยสงสัยว่าตอนทำ binding คุณเจอปัญหาแบบนี้ด้วยไหม
    • ไม่รู้มาก่อนเลยว่ามีโปรเจ็กต์ทำ Godot binding ด้วย Zig อยู่ด้วย ผมชอบทั้ง Godot และ Zig มาก เลยคาดหวังไว้สูงและจะติดตามต่อเนื่อง
  • นี่เป็นตัวอย่างที่ดีว่าการเขียนโปรแกรมที่ดีท้ายที่สุดคือการปรับตัวให้เข้ากับวิธีที่ระบบนั้นจัดเตรียมไว้ ไม่ว่าคุณจะคิดอย่างไรกับ OOP หรือการจัดการหน่วยความจำ ถ้าจะใช้ GTK คุณก็ต้องออกแบบอินเทอร์เฟซให้เข้ากับระบบชนิดข้อมูล GObject ไม่ทางใดก็ทางหนึ่ง เลี่ยงยังไงก็เลี่ยงไม่พ้น แต่พวกเราพยายามเลี่ยง และผลก็คือเกิดความยุ่งเหยิงมหาศาลตอนพยายามผูกอายุการใช้งานของอ็อบเจ็กต์ที่นับ reference กับอ็อบเจ็กต์ที่ไม่นับ reference เข้าด้วยกัน ในแอป Ghostty GTK มีบั๊กเกิดซ้ำ ๆ แบบว่าพอปล่อยหน่วยความจำฝั่ง Zig แล้ว หน่วยความจำฝั่ง GTK ไม่ถูกปล่อย หรือกลับกัน

    • เหตุผลที่ GTK มีโครงสร้างแบบนี้ ก็คือที่มาของการเกิด Vala นั่นเอง Vala ได้แรงบันดาลใจจาก C# ใช้ GObject และ transpile โค้ดไปเป็น C เพราะแบบนั้นแอป GTK จำนวนมากจึงจริง ๆ แล้วเขียนด้วย Vala ผมเองก็แอบเสียดายนิดหน่อยว่าถ้าใช้ภาษา D แทนน่าจะดีกว่าไหม D ให้ความรู้สึกเหมือน C# ที่คอมไพล์ได้ในหลายด้าน
    • การยอมจำนนต่อระบบที่แย่ไม่ใช่เรื่องดี แต่มันเป็นทางเลือกที่ใช้งานได้จริง
  • ไม่นับจุดยืนของผมเรื่อง OOP และการจัดการหน่วยความจำ ผมเห็นด้วยว่าถ้าใช้ GTK ก็หนีไม่พ้นที่จะต้องเข้าไปพัวพันกับระบบชนิดข้อมูล GObject ดังนั้นผมเลยตัดสินใจไม่ใช้ GTK โดยตรงไปเลย ผมเข้าใจคุณค่าของ UI theme ที่เป็นหนึ่งเดียวกัน แต่ในมุมมองของผม ข้อดีของ GTK ยังไม่คุ้มกับต้นทุนที่ต้องจ่ายเพื่อใช้งาน จากประสบการณ์ที่เคยแตะส่วนรอบ ๆ GTK ในแอปโอเพนซอร์ส ผมยิ่งมั่นใจว่ามุมมองของ GTK และ GObject ไม่ค่อยเข้ากับแนวคิดของผม ผมไม่ได้เกลียดการมีอยู่ของ GTK นะ ผมเลือกไม่ใช้มันก็พอ และผมโอเคกับทางเลือกนั้น แต่สิ่งที่แปลกคือบางคนกลับไม่มองว่านี่เป็นสิทธิ์ของผม มันก็เป็นแค่หนึ่งใน GUI toolkit จำนวนมาก แม้จะเป็น toolkit ที่ขัดเกลาทางเทคนิคมาอย่างดี แต่ผมก็อดคิดไม่ได้ว่าถ้าส่วนแบ่งของ GTK ต่ำกว่านี้อีกนิด งาน polish เหล่านั้นอาจถูกใช้กับ toolkit อื่นที่มีโครงสร้างดีกว่าก็ได้ แน่นอนว่าสิ่งที่ผมชอบไม่ได้แปลว่าทุกคนจะชอบเหมือนกัน เลยสงสัยว่าคนที่ใช้ GTK นั้น มีสักกี่คนที่ใช้เพราะจำเป็น และมีกี่คนที่คิดว่ามันคือเครื่องมือที่ดีที่สุดจริง ๆ

    • ผมเห็นด้วยกับส่วนที่บอกว่าสไตล์แบบ strongly opinionated ของ GTK และ GObject ก็ไม่ค่อยตรงกับความคิดของผมเหมือนกัน และผมก็รู้สึกว่าแนวทางของระบบนิเวศ Gnome เองก็ไม่ค่อยตรงกับผมเท่าไร การใช้ GTK สำหรับ Linux ใน Ghostty เป็นตัวเลือกที่ใช้งานได้จริงมาก เป้าหมายของ Ghostty เรื่องความเป็น native ของแต่ละแพลตฟอร์ม (โดยเฉพาะบนลินุกซ์) อธิบายไว้ที่นี่ GTK เป็นตัวเลือกที่ใช้กันแพร่หลายที่สุดบนลินุกซ์ และเข้ากับระบบนิเวศแอปส่วนใหญ่ได้เป็นธรรมชาติที่สุด จึงแทบเลี่ยงการตัดสินใจนี้ไม่ได้ ต่อจากนี้ก็หวังว่า libghostty จะเปิดทางให้บุคคลที่สามทำ frontend ได้หลากหลาย ตัวอย่างเช่น Wraith ซึ่งเป็น Ghostty frontend แบบ Wayland native ก็ดูเจ๋งมาก
    • ผมคิดว่าเหตุผลหลักที่ GTK ถูกใช้อย่างกว้างขวางบนลินุกซ์ ก็คือมันมี “C binding” นี่แหละ ทำให้แทบทุกภาษามี binding ให้ใช้ หรืออย่างน้อยก็สร้างอัตโนมัติได้ง่าย ในทางกลับกัน Qt ผูกกับ C++ และ Python มากเกินไปจนเข้าถึงยากลงมาก สิ่งสำคัญคือไม่ว่านักพัฒนาจะใช้ภาษาอะไร ก็ต้องรองรับเขาในที่ที่เขาอยู่ด้วย นอกจากนี้ ถ้าพูดถึงการเขียนเดสก์ท็อปแอปที่ซับซ้อน UI toolkit แบบ imperative รุ่นเก่ากลับใช้งานได้จริงกว่า และมี widget ที่ผ่านการพิสูจน์มาเยอะ รูปแบบการใช้งานก็เลยคุ้นเคย ส่วนแนวทางใหม่ ๆ กลับต้องลงมือทำเองตั้งแต่ชิ้นเล็ก ๆ และพอเริ่มซับซ้อนขึ้นนิดเดียวก็ลำบากมาก
    • ประเด็นที่ว่า “แม้จะบอกว่าไม่ใช้ GTK ก็ได้ แต่บางคนกลับทำเหมือนไม่ใช่สิทธิ์ในการเลือกของคนอื่น” ผมสงสัยว่าปกติคุณเจอข้อโต้แย้งแบบไหนบ้าง ในมุมผม GTK ทำเรื่อง accessibility และการป้อนอักขระที่ไม่ใช่อักษรโรมันได้ค่อนข้างดี ซึ่งเป็นเรื่องที่นักพัฒนาที่ทำเองมักไม่ค่อยใส่ใจ เลยดูเหมือนว่านี่จะเป็นจุดแข็งในการแข่งขันหลักของมัน
  • เรื่องน่าสนใจคือใน Ghostty และแอป GTK บางตัว มีอาการที่พอเมาส์ออกนอกหน้าต่างแล้วกลับเข้ามาใหม่ การคลิกสกอลล์ครั้งแรกจะถูกละเลยไป เป็นบั๊กเก่ามากที่มีรายงานครั้งแรกตั้งแต่ปี 2015 ลิงก์บั๊ก จนถึงตอนนี้ก็ยังไม่มีแผนจะแก้ และผู้ดูแลก็บอกให้รอ Wayland แทน

    • ดูเหมือนว่าจริง ๆ แล้วปัญหานี้ไม่ได้เกิดจาก GTK เอง แต่เกิดจาก XInput2 แน่นอนว่า GTK อาจแก้ทางด้วย heuristic แบบที่ Chromium ใช้ได้ แต่ต้นตอมันคือปัญหาจากชั้นบนกว่าอย่าง XInput2
    • ถ้าอ่าน bug report นั้นรวมถึง issue ที่ลิงก์ถึงกันไว้ จะเห็นว่ามีความพยายามจะแก้หลายครั้ง แต่สุดท้ายก็ต้องพึ่ง heuristic อยู่ดี และผลข้างเคียงที่เกิดขึ้นกลับแย่กว่าปัญหาที่พยายามจะแก้เสียอีก สุดท้ายแล้วมันเป็นปัญหาที่เริ่มจากรากฐานของ X11 ดังนั้นถ้าไม่มีการแก้ที่ต้นเหตุ การปรับปรุงอื่น ๆ ก็คงเดินหน้าได้ไม่มาก แต่ X11 ตอนนี้แทบจะอยู่ในโหมดบำรุงรักษาอย่างเดียวแล้ว ตราบใดที่แฟน ๆ ยังยืนยันว่า “มันทำงานได้สมบูรณ์อยู่แล้ว ไม่ต้องทำอะไรเพิ่ม” ก็คงหวังอะไรยาก วิธีที่เหลือจึงมีแค่รอการย้ายไป Wayland
  • ตรงที่บอกว่า “ผมตรวจสอบทุกขั้นตอนด้วย Valgrind” นี่จริง ๆ แล้วเป็นเรื่องที่ควรทำมาก แต่ผมเองไม่เคยทำเลยสักครั้ง และก็แทบไม่เคยเห็นนักพัฒนาคนอื่นทำแบบนั้นด้วย ปกติ Valgrind จะถูกใช้เฉพาะเวลามีบั๊กบางอย่างหรือประสิทธิภาพตกเท่านั้น ถ้าใช้เครื่องมืออย่าง Valgrind (โดยเฉพาะ Memcheck, Helgrind) เชิงรุกตลอดกระบวนการพัฒนา ความเสถียรของเครื่องมือก็น่าจะดีขึ้นมาก และยังจับบั๊กได้ตั้งแต่ตอนมันถูกใส่เข้ามา แทนที่จะต้องมานั่งไล่ย้อน commit เป็นร้อยในภายหลัง

    • ส่วนตัวผมเวลาใช้ C หรือ C++ จะรัน valgrind เป็นระยะอยู่เสมอ ข้อผิดพลาดที่ valgrind กับ asan จับได้ ส่วนใหญ่มักไม่แสดงออกมาเป็น crash ทันที แต่มักกลายเป็นบั๊กกวนใจที่เกิดเป็นครั้งคราวและสังเกตยาก ทำให้หาต้นเหตุได้ลำบากมาก บางส่วนก็เป็นช่องโหว่ด้านความปลอดภัยด้วย และพอ memory leak เล็ก ๆ สะสมไปเรื่อย ๆ จนสุดท้ายเกิดปัญหาใหญ่จริงขึ้นมา การมี leak เล็ก ๆ กองอยู่เต็มไปหมดก็ยิ่งทำให้หาต้นตอได้ยากขึ้น ดังนั้นการใช้เชิงรุกจึงเป็นเรื่องดี
    • ผมใช้ Valgrind (โดยเฉพาะ memcheck) เชิงรุกเพื่อเก็บปัญหาที่แก้ได้ง่ายก่อนจะไปดีบั๊กรายงานบั๊กแบบลงลึก แต่ปัญหาใหญ่ที่สุดคือมันมี overhead ด้านประสิทธิภาพสูงมาก ทำให้ประสบการณ์ตอนรันแบบโต้ตอบไม่ค่อยดีนัก ถึงอย่างนั้นการรันชุดทดสอบผ่าน Valgrind สักรอบก็ยังคุ้มค่ามาก
    • แต่ Valgrind นั้นช้ามากและต้นทุนสูงเกินกว่าจะใส่เข้าไปในลูปแก้โค้ด-คอมไพล์-ทดสอบได้โดยตรง อาจใช้ในรอบทดสอบ เช่น nightly หรือระบบอัตโนมัติได้ แต่ถ้าจะผสานให้ดีจริงก็ต้องมีงานเพิ่มอีกพอสมควร
  • ตอนใช้ Ghostty ผมรำคาญมากที่บน Mac วางข้อความหลายบรรทัดลงใน nano ไม่ได้ ดูเหมือนจะเกี่ยวกับวิธีที่เทอร์มินัลจัดการ “bracketed pasting” แต่แปลกที่ iterm2 หรือ term กลับไม่มีปัญหานี้

    • Ghostty ในฐานะโปรแกรมแทนเทอร์มินัลนั้นผมพอใจอยู่ 99% แต่ปัญหา copy/paste นี่น่าหงุดหงิดจริงและเจอทุกวัน
    • ตั้งแต่ใช้ Ghostty เป็นเทอร์มินัลหลักบนเครื่องใหม่ สิ่งที่ขาดที่สุดคือฟังก์ชันค้นหา ปกติผมใช้คีย์ลัดค้นหาข้อความใน output บ่อยมาก แต่ตรงนี้ยังไม่มี จริง ๆ แล้ว issue นี้ก็เป็นปัญหาที่ถูกพูดถึงบ่อยที่สุดด้วย
    • ตอน remote เข้า Ubuntu ก็รัน nano ใน Ghostty ไม่ได้เลย
      $ nano
      Error opening terminal: xterm-ghostty.
      
      แต่ในสภาพแวดล้อมเดียวกัน ถ้าใช้ macOS Terminal หรือเทอร์มินัลฝังใน VSCode กลับทำงานได้ตามปกติ
    • อาการแบบนี้น่าจะเป็นบั๊กจริง ๆ แนะนำให้รายงานบั๊ก
    • สิ่งที่ร้ายแรงที่สุดคือไม่มีการค้นหาคำสั่งแบบ Cmd+F
  • สงสัยว่าถ้าใช้ Rust แทน Zig จะป้องกันข้อผิดพลาดด้านหน่วยความจำได้ไหม ดูเหมือนปัญหาส่วนใหญ่จะมาจากการเชื่อมต่อระหว่าง Zig/C ดังนั้น Rust ก็คงคล้ายกัน ในฐานะนักพัฒนา Go ผมเดาว่าเวลาเชื่อมกับ C แบบขนาดใหญ่ มีภาษาไหนที่ให้เครื่องมือด้านความปลอดภัยมากกว่านี้หรือเปล่า

    • ถ้าเป็น Rust ก็น่าจะกันปัญหาได้อยู่หนึ่งอย่าง แต่ที่เหลือก็คงเหมือนเดิม อย่างที่คุณชี้ไว้ ปัญหาทั้งหมดอยู่ที่ขอบเขตและความหมายของ C API ดังนั้นความปลอดภัยจริง ๆ จึงขึ้นอยู่กับคุณภาพของ wrapper Rust มีระบบนิเวศของ wrapper ที่ผ่านการพิสูจน์มาแล้วเยอะ จึงอาจเสี่ยงน้อยกว่า wrapper ที่เขียนเองด้วย Zig แต่สุดท้ายก็ไม่ได้ต่างกันมาก ตัวอย่างเช่นการเข้าถึงหน่วยความจำแบบ undefined ซึ่ง Rust น่าจะจับได้ ถูกแก้ไว้จริงใน PR นี้ ในความเป็นจริง หน่วยความจำที่ผิดถูกคัดลอกไปยังเฟรมแรก แต่ไม่ได้ถูกใช้งานหรือส่งต่อไปไหน จึงไม่ร้ายแรงนัก ถึงอย่างนั้นมันก็ยังไม่ถูกต้องแน่นอน
    • Rust เองก็ยังต้องจัดการหน่วยความจำและอายุการใช้งานแบบ manual ที่ขอบเขต FFI กับ C/GObject อยู่ดี ตัวตรวจ borrow ของ Rust ไม่สามารถตรวจสอบการใช้หน่วยความจำของโค้ดภายนอกได้
    • ประเด็นหนึ่งของบทความก็คือ การจับคู่ zig + valgrind ทำให้เจอปัญหาหน่วยความจำน้อยกว่าที่คาดไว้มาก
    • การเขียน C binding ด้วย Rust ยากกว่ามาก ดังนั้นการทำ gtk binding ด้วย rust เองก็อาจจะทำไม่ได้เลย
  • พอใช้แอปที่อิง GPU อย่าง Ghostty (รวมถึง Alacritty, WezTerm, Zed ฯลฯ) ก็รู้สึกว่ามันเร็วและดีกว่า แต่ในทางกลับกันมันก็ยิ่งเผยให้เห็นข้อจำกัดของไดรเวอร์ Nvidia ชัดขึ้นอย่างน่าขัน เมื่อก่อนแทบไม่ใช้ GPU เลยไม่รู้ แต่พออยู่ในสภาพแวดล้อมที่ไม่มี compositor อย่าง Regolith i3wm หรือในสภาพแวดล้อม sway/wayland ก็เจอว่าไดรเวอร์ nvidia แย่มากทั้งเรื่องแชร์หน้าจอ การตื่นจาก sleep และการ crash ลองหลายเวอร์ชันแล้ว (550/560/575/580) ก็เหมือนเดิมหมด เพิ่งมารู้ไม่นานนี้เองว่ามันแย่มานานแล้ว

    • ผมเองก็มีประสบการณ์คล้ายกันบน Wayland บน X11 ถ้าปิด compositing effects ออก ทั้ง 1050Ti และการ์ด AMD เก่า (ที่ต้องใช้ไดรเวอร์ radeon) ก็ทำงานได้ปกติดี แต่บน Wayland กลับมีปัญหากระตุก crash และภาพแตก
  • ผมเคยทำแอปขนาดใหญ่ตัวหนึ่งได้โดยที่ระบบชนิดข้อมูลของ GTK แทบไม่ส่งผลต่อโค้ดเลย แต่ก็ต้องแลกด้วยการเชื่อมทุกคอมโพเนนต์เข้าหากันด้วยการ bind แค่ lambda แทนที่จะใช้การสืบทอดคลาสหรือการขยายแบบปกติ ผลลัพธ์สุดท้ายไม่ได้เละเทะอะไรนัก แต่สำหรับนักพัฒนาที่คุ้นกับสไตล์ GTK แบบดั้งเดิมอาจรู้สึกสับสนได้

  • ผมไม่เข้าใจกระแสความสนใจเกินจริงที่มีต่อ Ghostty เลย UI ก็มีแค่แท็บกับเมนูคลิกขวา เลยสงสัยว่าการทำงานผสานแบบนี้และถึงขั้น rewrite จะคุ้มค่าหรือเปล่า เดาว่าอาจกำลังจะเพิ่ม GUI ที่ทรงพลังแบบ iterm2 ด้วยหรือไม่ Kitty วาดแท็บเองด้วย OpenGL จึงปรับแต่งได้เต็มที่ และประหยัดเวลาจากการไม่ต้องไปผสานกับเฟรมเวิร์กซับซ้อน เลยรีบทำฟีเจอร์ใช้งานจริงได้มาก เช่น เอาผลลัพธ์คำสั่งล่าสุดไปครอบด้วย pager เพื่อแสดงผล เป็นต้น และ Kitty ก็รองรับการ remote ได้ดีด้วย

    • UI ของ Ghostty ไม่ได้มีแค่แท็บ แต่ยังมี split, แบนเนอร์ “โปรเซสสิ้นสุดแล้ว”, ไดอะล็อกยืนยันการปิด, ไดอะล็อกเปลี่ยนชื่อ, การตรวจจับการวางข้อความที่ไม่ปลอดภัย, กระดิ่งแจ้งเตือนแบบมีแอนิเมชัน, ดรอปดาวน์เทอร์มินัล, แถบความคืบหน้า และอื่น ๆ มากกว่าที่คิด บน Mac ยังมีการผสานกับ Apple Shortcuts และ Spotlight ด้วย แน่นอนว่าถึงไม่มีสิ่งเหล่านี้ ก็ยังสามารถทำทั้งหมดแบบล้วน ๆ โดยไม่ใช้ GUI toolkit ได้ แต่ภารกิจของ Ghostty คือการใช้ native toolkit ของแต่ละแพลตฟอร์ม เพื่อให้แอปรู้สึก “native จริง ๆ” ถ้าคุณไม่ชอบแนวทางนี้ การใช้แท็บข้อความแบบ Kitty ก็เป็นตัวเลือกที่ดี ความต่างอยู่ที่คุณค่าและลำดับความสำคัญที่แต่ละคนเลือก ต่อไปยังมีแผนสำหรับส่วนขยาย GUI อีกหลากหลาย และจะผสานฟีเจอร์ native ของแต่ละแพลตฟอร์มให้ลึกขึ้นอีก เช่น การซิงก์กับ iCloud
    • สำหรับคำกล่าวที่ว่า “Kovid ทำฟีเจอร์ได้เร็วกว่า” ควรระวังไว้หน่อย เพราะบัญชีนี้มีประวัติที่น่าสงสัยว่าอาจเป็น Kovid เองจริง ๆ ผมเคยเห็นเขาแนะนำ Kitty แบบทำเหมือนเป็นกลางใน HN และ Reddit พร้อมกับวิจารณ์นักพัฒนาคนอื่น ลองดูคอมเมนต์เก่า ๆ เพิ่มได้จากลิงก์นี้
    • นอกจากคำอธิบายเชิงบวกข้างบนแล้ว ผมคิดว่าการมาของ ‘libghostty’ นี่แหละคือ game changer มันเป็นเทอร์มินัล implementation ที่ทรงพลังแบบ WebKit คือใครจะ drop-in เข้าไปใช้ก็ทำงานได้ทันที
    • ผมเองก็เคยลองสลับเทอร์มินัลไปมาอยู่พักใหญ่ Ghostty อาจไม่ใช่สิ่งที่สมบูรณ์แบบตามอุดมคติ แต่พอหาตัวที่พอเหมาะพอใจไม่ได้ ผมก็ย้ายมาใช้มันอยู่ดี สำหรับผม แค่นี้ก็มีความหมายเพียงพอแล้ว โดยรวมแล้ว จุดแข็งของมันไม่ใช่เพราะมี ‘เหตุผลตัดสินใจเด็ดขาด’ อะไรเป็นพิเศษ แต่เป็นเพราะมันไม่มีปัญหาใหญ่จนทำให้เลิกใช้ ซึ่งในทางหนึ่งกลับถือเป็นข้อดี
    • ฟอนต์เรนเดอร์ใน Ghostty สวยกว่าใน Kitty มาก ส่วน Neovide สวยกว่าอีก แต่ยังไม่รองรับแท็บและกินแบตมากกว่า