1 คะแนน โดย GN⁺ 2025-06-04 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ความยืดเยื้อของการจัดการข้อผิดพลาด ในภาษา Go เป็นหนึ่งในข้อร้องเรียนหลักของผู้ใช้มาอย่างยาวนาน
  • มีการหารือและทดลอง ข้อเสนอปรับปรุงไวยากรณ์หลายแบบ (เช่น check/handle, try, ตัวดำเนินการ ? เป็นต้น) แต่ทั้งหมดถูกปัดตกเพราะยังไม่มีฉันทามติจากชุมชนมากเพียงพอ
  • สิ่งที่ถูกพิจารณาอย่างสำคัญคือ ผลกระทบในวงกว้างต่อโค้ด เครื่องมือ เอกสาร ฯลฯ จากการเปลี่ยนภาษา และหลักการรักษาความเรียบง่ายอันเป็นเอกลักษณ์ของ Go
  • ด้วย ความชัดเจน ความสะดวกในการดีบัก ของวิธีปัจจุบัน รวมถึงความชอบของผู้ใช้บางส่วน จึงมีเหตุผลไม่มากพอที่จะต้องนำการเปลี่ยนแปลงทางไวยากรณ์เข้ามา
  • ในอนาคตที่มองเห็นได้ยังไม่มีแผนเปลี่ยนไวยากรณ์การจัดการข้อผิดพลาด และข้อเสนอที่เกี่ยวข้องทั้งหมดจะถูกปิดโดยไม่มีการศึกษาต่อเพิ่มเติม

การตั้งประเด็นเรื่องความยืดเยื้อของการจัดการข้อผิดพลาดใน Go

  • หนึ่งในข้อร้องเรียนเก่าแก่ของ Go คือ ไวยากรณ์การจัดการข้อผิดพลาดยืดเยื้อเกินไป
  • ตัวอย่างที่เด่นชัดคือแพตเทิร์นอย่าง if err != nil ที่ปรากฏซ้ำๆ ในโค้ด
  • ยิ่งเป็นโปรแกรมที่ต้องเรียก API หลายครั้ง ไวยากรณ์นี้ก็ยิ่งเด่นชัด และเกิดปรากฏการณ์ที่โค้ดจัดการข้อผิดพลาดมีมากกว่าลอจิกหลัก
  • ในแบบสำรวจผู้ใช้ประจำปี ข้อร้องเรียนนี้ยังคงถูกกล่าวถึงในอันดับต้นๆ อย่างต่อเนื่อง

การหารือกับชุมชนและข้อเสนอระยะแรก

  • ทีม Go ให้ความสำคัญกับฟีดแบ็กจากชุมชน จึงศึกษาข้อเสนอปรับปรุงการจัดการข้อผิดพลาดมาอย่างต่อเนื่อง
  • ในการหารือโครงการ Go 2 ปี 2018 Russ Cox ได้สรุปแก่นของปัญหาการจัดการข้อผิดพลาดอย่างเป็นทางการ
    • มีข้อเสนอ กลไก check และ handle ของ Marcel van Lohuizen ปรากฏขึ้น
    • รวมถึงการวิเคราะห์เปรียบเทียบกับภาษาอื่นที่คล้ายกันและการพิจารณาทางเลือกหลายแบบ
  • แม้ว่าวิธีนี้จะช่วยให้โค้ดกระชับขึ้นจริง แต่ก็ไม่ได้ถูกรับมาใช้เพราะ เพิ่มความซับซ้อน

ข้อเสนอ try และสิ่งที่ตามมา

  • ในปี 2019 มีข้อเสนอ ฟังก์ชันในตัว try ที่เรียบง่ายกว่ามาก
    • นำเฉพาะความสามารถของ check มาใส่เป็นโค้ด และตัด handle ออก
    • ข้อเสนอนี้ถูกวิจารณ์ว่า ซ่อนการไหลของการควบคุม และสุดท้ายก็ถูกยกเลิกท่ามกลางแรงต้านจากชุมชน
  • ประสบการณ์นี้ทำให้เห็นถึง ความเสี่ยงของข้อเสนอที่ดูสมบูรณ์โดยยังไม่ได้รับฟีดแบ็กเพียงพอ
    • ยืนยันว่าข้อเสนอการเปลี่ยนแปลงขนาดใหญ่ควรเปิดรับความคิดเห็นที่กว้างขวางกว่านี้ตั้งแต่ช่วงออกแบบแรกเริ่ม

ความพยายามเพิ่มเติมและข้อเสนอที่หลากหลาย

  • มีข้อเสนอรูปแบบแปรผันและแนวทางจัดการข้อผิดพลาดทางเลือกอีกจำนวนมากเกิดขึ้นในชุมชนอย่างต่อเนื่อง
    • Ian Lance Taylor ได้สรุปสถานะไว้ใน umbrella issue และยังมีการรวบรวมกรณีตัวอย่างต่อเนื่องใน Go Wiki และบล็อก
  • ในปี 2024 มีข้อเสนอให้นำ ตัวดำเนินการ ? ที่ยืมมาจาก Rust มาใช้
    • แม้การทดสอบการใช้งานขนาดเล็กจะมีฟีดแบ็กว่าเข้าใจได้ง่าย แต่ก็ยังไม่สามารถสร้างฉันทามติได้ท่ามกลางความคิดเห็นที่หลากหลาย

ภาวะชะงักงันของการถกเถียงและข้อสรุป

  • แม้จะมีข้อเสนออย่างเป็นทางการและไม่เป็นทางการเกิน 3 รายการ และข้อเสนอจากชุมชนอีกหลายร้อยรายการ แต่ทั้งหมดก็ถูกปัดตกเพราะ ขาดความเห็นพ้องหรือฉันทามติที่เพียงพอ
  • แม้แต่ กลุ่มสถาปนิกภายในของ Go เองก็ยังไม่มีความเห็นตรงกันเรื่องทิศทาง
  • จึงมีการตัดสินใจว่าจะหยุดความพยายามเปลี่ยนไวยากรณ์การจัดการข้อผิดพลาดไปก่อน จนกว่าจะมีการเปลี่ยนแปลงของสถานการณ์หรือเกิดฉันทามติพิเศษขึ้น

เหตุผลหลักที่สนับสนุนการคงวิธีปัจจุบันไว้

  • หากใส่ syntactic sugar มาตั้งแต่การออกแบบภาษาในช่วงแรกอาจไม่เกิดข้อถกเถียง แต่ปัจจุบันระบบนิเวศได้คุ้นชินกับ แนวทางที่ใช้มานาน 15 ปี แล้ว
  • หากเพิ่มไวยากรณ์ใหม่ ก็ย่อมมีความกังวลเรื่อง ช่องว่างด้านสไตล์โค้ดระหว่างผู้ใช้เดิมกับผู้ใช้ใหม่ และการสูญเสียความสม่ำเสมอ
  • เรื่องนี้ยังสอดคล้องกับปรัชญาการออกแบบของ Go ที่ไม่ทำสิ่งเดียวกันได้หลายวิธี และยึดหลัก ความกระชับ/ความสม่ำเสมอ
    • แม้แต่การอนุญาตให้ประกาศซ้ำในรูปแบบประกาศตัวแปรสั้น (:=) ก็เป็นการเปลี่ยนแปลงรองที่เกิดจากการจัดการข้อผิดพลาด
  • ไวยากรณ์การจัดการข้อผิดพลาดที่ชัดเจน (ผ่าน if) มีข้อดีเชิงสัญชาตญาณต่อการอ่านโค้ด การดีบัก และการตั้ง breakpoint
  • การเปลี่ยนภาษาเองก็เป็นภาระใหญ่ทั้งในแง่ขอบเขตของการเปลี่ยนจริง (โค้ด เอกสาร เครื่องมือ ฯลฯ) และต้นทุน

การปรับปรุงทางเลือกและทิศทางในอนาคต

  • การ เพิ่มความสามารถของไลบรารีมาตรฐาน (เช่น การเพิ่ม cmp.Or) อาจช่วยลดโค้ดซ้ำบางส่วนได้
  • ด้วย การพับโค้ดใน IDE การเติมโค้ดอัตโนมัติ การใช้ LLM ฯลฯ เครื่องมือพัฒนาจึงช่วยบรรเทาความยืดเยื้อในงานจริงได้ระดับหนึ่ง
  • ในกลุ่มผู้ใช้ Go หลักๆ (เช่น ผู้เข้าร่วมงาน Google Cloud Next) ความเห็นเชิงลบต่อความจำเป็นในการเปลี่ยนภาษามีมากกว่า
    • ยิ่งใช้ Go มากขึ้น ปัญหาเรื่องความยืดเยื้อก็ยิ่งรู้สึกน้อยลงในทางปฏิบัติ

เหตุผลที่สนับสนุนความจำเป็นของการปรับปรุงไวยากรณ์

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

ข้อสรุปสุดท้ายและนโยบายต่อจากนี้

  • จากการยอมรับว่ายังไม่มีฉันทามติหรือความเปลี่ยนแปลงที่เป็นรูปธรรม จึงประกาศยุติการหารือและข้อเสนอเรื่องการเปลี่ยนภาษาเชิงไวยากรณ์เพื่อการจัดการข้อผิดพลาดทั้งหมดในอนาคตอันใกล้
  • กระบวนการหารือและการศึกษาที่ผ่านมามีส่วนช่วยต่อระบบนิเวศและการปรับปรุงกระบวนการของ Go ทางอ้อม
  • หากในอนาคตมีการนิยามปัญหาที่ชัดเจนขึ้นและเกิดฉันทามติ ก็อาจกลับมาเปิดการหารือได้อีก
  • ในช่วงนี้จะมุ่งเน้นที่ การรักษาความแข็งแกร่งและความเรียบง่ายของ Go เอง มากกว่าการลองแนวทางใหม่ๆ

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

 
GN⁺ 2025-06-04
ความเห็นจาก Hacker News
  • ถ้าอยากเสนออย่างง่าย ๆ ว่าทีม Go น่าจะเลือกทางอื่นได้ อยากให้ลองดู วิกิ Go2ErrorHandlingFeedback หรือ ค้นหา issue ใน GitHub ก่อน ไอเดียแทบทั้งหมดที่ถูกเสนอไปนั้นถูกพูดคุยกันอย่างจริงจังมาแล้ว และในฐานะผู้ใช้ที่ซาบซึ้งกับแนวทางที่โปร่งใสของทีม Go ก็รู้สึกสนุกกับการใช้ Go ทุกวันมาก

    • เอกสารร่างการออกแบบพูดถึง C++, Rust, Swift แต่แทบไม่เห็นสิ่งที่ผมหาอยู่ เช่น do-notation/for-comprehensions/monadic-let ของภาษาสายฟังก์ชันอย่าง Haskell/Scala/OCaml เลย ทีม Go ดูราวกับเป็นปรมาจารย์ด้านการออกแบบภาษา แต่สุดท้ายกลับติดข้อจำกัดของ static type ที่ไม่มี parametric polymorphism แบบ Java จนหาคำตอบเรื่องการจัดการข้อผิดพลาดไม่ได้ ผมมองว่านี่เป็นปัญหาที่มาจากการออกแบบภาษาตั้งแต่รากฐาน

    • แม้จะเป็นเอกสารที่เขียนโดยคนเก่งและมีประสบการณ์มาก ก็ยังน่าแปลกมากที่ไม่มีการกล่าวถึงทางออกอย่าง Maybe/Either monad ของ Haskell และตัวดำเนินการ bind (do-notation) เลย ทั้งที่จริง ๆ มันไม่ได้ยากหรือวิชาการเกินไป และเป็นวิธีที่สวยงามและผ่านการพิสูจน์มาแล้วสำหรับการส่งต่อข้อผิดพลาดอย่างปลอดภัย จึงไม่เข้าใจว่าทำไมชุมชน Go ถึงไม่เอาแนวคิดนี้มาใช้ ขอบคุณที่มีหน้านี้อยู่ แต่การมองข้ามวิธีแก้ที่โด่งดังขนาดนี้ก็ยังเข้าใจได้ยาก

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

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

  • คิดว่าผู้ใช้ได้ประโยชน์จากความอนุรักษนิยมของ Go ที่ระวังมากในการเพิ่มฟีเจอร์ใหม่ให้ภาษา ฝั่ง Swift มีการเปลี่ยนฟีเจอร์เยอะจนเรียนรู้ยาก และแม้บน Mac รุ่นใหม่ก็ยังเจอกรณีที่แค่โปรเจกต์ง่าย ๆ โปรเจกต์เดียวก็บิลด์ไม่ผ่านอยู่บ่อย ๆ เพราะคีย์เวิร์ดเพิ่มและเปลี่ยนอยู่ตลอด ทำให้ Swift ใช้งานต่อเนื่องได้ไม่ดีเท่าไร ขณะที่จุดแข็งของ Go คือความสม่ำเสมอ

  • ครั้งหนึ่งเคยมีสถานการณ์พิเศษที่ฟังก์ชัน Go ต้องคาดหวังให้ฟังก์ชันภายในเกิด error และถ้าฟังก์ชันภายในไม่ error กลับต้องถือว่าฟังก์ชันนั้นผิดพลาดแทน ในโครงสร้างที่ไม่ค่อยเจอแบบนี้จึงต้องแตกแขนงด้วย if err == nil แต่ด้วยความเคยชินเลยเผลอเขียน if err != nil ตามแพตเทิร์นเดิม ทำให้ใช้เวลานานมากกว่าจะหาความผิดพลาดเจอ เลยคิดว่าถ้าภาษาช่วยแยกเชิงไวยากรณ์ระหว่าง if err != nil ที่ใช้บ่อยกับ if err == nil ที่ใช้ไม่บ่อย ก็น่าจะช่วยลดความผิดพลาดได้

    • ทุกครั้งที่ใช้ if err == nil ผมจะใส่คอมเมนต์ // inverted เพื่อเน้นแพตเทิร์น ถ้าภาษาจัดการให้อัตโนมัติได้ก็คงดี แต่ตอนนี้อย่างน้อยวิธีนี้ก็ช่วยให้แยกความต่างได้ชัดขึ้น
    • จริง ๆ แล้วนี่กลับเป็นจุดยืนที่คัดค้านการเปลี่ยนไวยากรณ์ เพราะแพตเทิร์น if err == nil { return ... } ที่ใช้บ่อยอาจยิ่งดูแปลกตาในโค้ดก็ได้ หลายคนชอบวิธีจัดการ error ของ Go ในปัจจุบันเพราะมันชัดเจนและอ่านง่าย
    • ความสับสนแบบเดียวกันนี้ก็เกิดได้กับแพตเทิร์นอย่าง if fruit != "Apple" ดังนั้นโดยแก่นแล้วมันไม่ใช่ปัญหาเฉพาะของการจัดการ error แต่เป็นปัญหาทั่วไปของการแตกแขนงตามสถานะ Error เองก็สุดท้ายเป็นเพียงค่าสถานะอีกแบบหนึ่ง
    • ใน IDE หรือการตั้งค่าฟอนต์ อาจเรนเดอร์ if err != nil ให้เหมือนสัญลักษณ์พิเศษจนกลืนไปกับพื้นหลังอย่างเป็นธรรมชาติและเด่นน้อยลง แล้วทำให้ if err == nil ที่เขียนต่างออกไปโดดเด่นขึ้น จึงอาจช่วยป้องกันความผิดพลาดได้ในระดับเอดิเตอร์
    • มีข้อเสนอว่าน่าจะปรับปรุงการอ่านได้ด้วยการให้เอดิเตอร์ย่อรูปแบบอย่าง if err … { ตอนแสดงผล
  • ผมชอบวิธีจัดการ error แบบ explicit ของ Go มันทำให้เข้าใจง่ายว่าฟังก์ชันจะสำเร็จเสมอ (minimal error) หรืออาจล้มเหลวได้ ฟังก์ชันที่มีโอกาสล้มเหลวต้องถูกจัดการก่อนเสมอจึงจะไปขั้นถัดไปได้ หลายภาษาพอใช้ exception พอเกิดข้อผิดพลาดก็จะโยนไล่ขึ้นไปตาม stack จนกว่าจะมี catch ซึ่งมักบอกได้แค่ว่า error เกิดที่ไหนแต่ให้คำใบ้เชิงปฏิบัติไม่มากนัก ใน Go เรามีตัวเลือกที่ชัดเจนดังนี้: 1) ไม่สนใจ error 2) เจอ error แล้ว return ทันที 3) wrap error เพื่อเพิ่มข้อมูลที่มีประโยชน์ 4) ตีความ error เฉพาะแล้วแตกแขนงจัดการ (เช่น แปลงเป็น 404) ใน Go2 อยากลองเพิ่มชนิด Result<Value, Failure> หรือประเภท error ที่เฉพาะเจาะจงและแจกแจงได้มากกว่านี้ คิดว่าการนำเข้าใน Go 2 จะเหมาะกว่าเพื่อรักษาความเข้ากันได้กับ Go 1

    • จากประสบการณ์ นโยบายการจัดการ error ต้องเป็นสิ่งที่ผู้เรียกตัดสินใจเองเสมอ การไปจัดการกันที่ stack ชั้นล่างไม่ใช่แนวทางที่ดี สุดท้ายมันมักกลายเป็นงานซ้ำ ๆ แบบง่าย ๆ คือ wrap error แล้วส่งต่อขึ้นไปชั้นบน
    • ที่เรียกว่า “การจัดการ error ของ Go” จริง ๆ แล้วภาษาแทบทั้งหมดนอกจาก JavaScript กับ Python ก็มีอยู่แล้ว ไม่ว่าจะเป็นภาษาสายฟังก์ชันหรือ Rust, Java ฯลฯ สุดท้ายถ้ามี generics ก็สามารถทำการจัดการ error แบบ Go ได้ในภาษาไหนก็ได้ ถ้าเทียบอยู่แค่กับ JS หรือ Python มันก็เป็นแค่แพตเทิร์นที่พบได้ทั่วไป
    • การที่ “ถ้าฟังก์ชันล้มเหลวแล้วต้องจัดการเสมอ” นี่เองคือจุดล้มเหลวของ Go เพราะใน Go จริง ๆ แล้วสามารถเพิกเฉยต่อ error ได้ทั้งหมด ดังนั้นถ้าอยากสร้างซอฟต์แวร์ที่ robust จริง ๆ วิธีของ Go อาจกลับเป็นจุดอ่อน
    • มีความเห็นเชิงขมขื่นว่า Go2 สุดท้ายก็จะเป็นเพียง “ห้องทดลองที่ไม่มีวันออกจริง”
  • ตอนแรกไม่ค่อยชอบวิธีจัดการข้อผิดพลาดของ Go แต่พออ่าน บล็อกโพสต์ errors-are-values แล้วเริ่มใช้ panic(err) ในจุดที่เหมาะสม กลับรู้สึกพอใจมากขึ้นมาก สำหรับสภาวะผิดปกติที่โค้ดระดับบนไม่ควรจัดการเอง การใช้ panic ช่วยลดแขนง error จุกจิกในโค้ดลงได้มาก วิธีบริหารข้อผิดพลาดแบบนี้ช่วยงานจริงได้มากทีเดียว

    • มีข้อโต้แย้งว่าเหตุผลแบบนี้กลับยิ่งปกป้องการจัดการข้อผิดพลาดที่อ่อนของ Go ไม่ได้ และถึงปรับปรุงให้ดีขึ้น ข้อดีเหล่านี้ก็ไม่ได้หายไป
    • มีการพูดถึงว่า PHP ก็มีการจัดการ error ตามระดับหรือการกด error ที่ call site ด้วยตัวดำเนินการ @ ได้ และ bash ก็มีเทคนิคจัดการ error อย่าง -e
    • ตอนเห็น flow แบบ try/catch/finally ใน C# ครั้งแรกก็รู้สึกสดใหม่ แต่ตอนนี้กลับชอบตรรกะแบบเรียบง่ายของ Go มากกว่า ถึงจะมีปริมาณโค้ดสูง (Loc) แต่ข้อดีคือ flow ของโค้ดชัดเจนจริง ๆ
    • มีการกล่าวว่า error แบบ sum type ของ Rust ก็อยู่ในกระบวนทัศน์ ‘errors are values’ เหมือนกัน
  • มีข้อโต้ตอบเชิงขำ ๆ ว่า เมื่อบอกว่าถ้าจัดการ error จริง ๆ แล้วความเยิ่นเย้อจะถูกกลบไปไว การสร้าง manual stack trace นับว่าเป็น “การจัดการ” จริงหรือ? ถ้าตามนิยามของ Go งั้น exception ก็ถือว่าเป็นการจัดการเหมือนกันไม่ใช่หรือ?

    • ก็ยังสงสัยว่า stack trace ยาวหลายสิบบรรทัดนั้นเป็นข้อมูลที่ชัดเจนจริงหรือไม่ ส่วนตัวคิดว่า wrap error แค่บรรทัดเดียวมีประสิทธิภาพกว่ามาก และยังช่วยให้จัดระเบียบ log ได้ด้วย ใช้ Go มาสิบกว่าปีแล้วก็ไม่เคยต้องการข้อมูล stack ที่ยืดยาวถึงขั้นรวม runtime function เลย
  • ผมไม่ชอบที่บทความนี้ทำเหมือนปัญหาของการจัดการ error ใน Go เป็นแค่เรื่อง “ไวยากรณ์มันเยิ่นเย้อ” ปัญหาจริงในมุมมองผมคือ 1) error หลุดหายเงียบ ๆ หรือถูกมองข้ามโดยไม่ตั้งใจได้ง่าย 2) ส่งต่อหรือเก็บผลลัพธ์ของฟังก์ชันไว้เหมือนค่าอย่างสะดวกไม่ได้ 3) error ซ้อนอย่าง errors.Is เข้ากับ type system ได้อย่างกระอักกระอ่วน 4) สลับกรณีตาม error ได้ยาก 5) มาตรฐานไลบรารีใช้ sentinel value เยอะ 6) เข้ากับ generics ไม่ดีจนต้องพึ่งแพ็กเกจ เป็นต้น

    • โปรแกรมเมอร์ Go ระดับมืออาชีพราว 90% ต้องเขียน test case ให้ครอบคลุมแต่ละแขนงของการ return error เพื่อดัน coverage ให้ถึง ซึ่งเป็นงานที่ไม่จำเป็นในภาษาที่ใช้ exception
    • ผมไม่คิดว่าข้อกล่าวหาว่าบทความนี้ชูประเด็นหลักเป็น It’s too verbose (มันเยิ่นเย้อเกินไป) จะตรงกับข้อเท็จจริง ต่อให้เปลี่ยนไวยากรณ์ก็ไม่ได้ช่วยแก่นของปัญหามากนัก
    • ก็มีมุมมองว่าความเร็วในการเปลี่ยนแปลงของ Go ที่ช้ามากนี่เอง (แม้แต่ generics ก็ใช้เวลานาน) กลับเป็นข้อดี
    • ในฐานะ Googler รู้สึกผิดหวังกับการตัดสินใจของทีม Go อีกครั้ง
  • ใน Elixir (และ Erlang) โดยทั่วไปฟังก์ชันจะคืนค่าเป็นทูเพิล {:ok, result} หรือ {:error, description} ด้วยไวยากรณ์ with ของ Elixir จึงสามารถรวบการจัดการ error ไว้ด้านล่างของบล็อก ทำให้อ่านง่ายขึ้นมาก ถ้า Go มีอะไรคล้าย with เข้ามา ก็อาจทำให้อ่านง่ายขึ้นได้ โดยให้รันต่อเนื่องเฉพาะตอนที่ error เป็น nil แล้วค่อยมีบล็อก handler อยู่ล่างสุด

    • เพราะ Go ติดปัญหาเรื่องฉันทามติของชุมชน แม้แต่ฟีเจอร์มีคุณค่าอย่าง sum type พื้นฐาน การจัดการ error หรือ package management ก็ยังเพิ่มได้ช้ามาก generics ใช้เวลา 13 ปี, การจัดการ error 16 ปี, การจัดการแพ็กเกจ 9 ปี เป็นการเปลี่ยนแปลงที่ช้ามาก ความรอบคอบก็สำคัญ แต่พอไล่ตามความสมบูรณ์แบบมากไปก็ทำให้การตัดสินใจถูกเลื่อนออกไปเรื่อย ๆ อย่างน่าเสียดาย
    • แพตเทิร์นการคืนค่าหลายค่าใน Go บางมุมก็มองว่าแปลก เพราะสิ่งเดียวที่ทำได้กับฟังก์ชันที่คืนหลายประเภทคือเอาไปกำหนดให้ตัวแปร
  • มีมุมมองว่าไม่เข้าใจว่าทำไมถึงไม่เดินตามสไตล์ Rust ไปเลย โดยเฉพาะตอนนี้ที่มี generics แล้ว การทำอะไรคล้ายกันก็น่าจะเป็นไปได้ไม่ยาก แม้ตัวดำเนินการ ? ของ Rust จะสะดวก แต่ไม่ค่อยเห็นด้วยกับเหตุผลที่ว่ามันส่งเสริมให้มองข้ามข้อผิดพลาด เพราะในความเป็นจริง Go เองก็มีกรณีมากมายที่มองข้ามค่าที่คืนเป็น error ได้โดยไม่เกิด compile error ถ้าอยากป้องกันความผิดพลาดจริง ๆ ก็ควรบังคับให้คืน Result แบบสไตล์ Rust ไปเลย ถ้าจะเถียงเรื่องความสะดวกสบาย งั้นก็ควรห้าม panic ไปด้วยไม่ใช่หรือ เป็นความเห็นที่แรงพอสมควร

    • มีความเห็นว่าเหตุที่ Go เอา Result เข้ามาไม่ได้ เป็นเพราะไม่มี sum type และมีการออกแบบแปลกเฉพาะตัวที่กำหนดให้ทุก type ต้องมี zero value
    • สำหรับคำกล่าวที่ว่าฟีเจอร์อำนวยความสะดวกอย่าง “ตัวดำเนินการ ?” จะทำให้ “เลิกใช้ wrapped error” นั้น ก็มีข้อโต้แย้งว่าสามารถออกแบบให้ฟีเจอร์แบบนั้นสนับสนุนการ wrapping ได้เหมือนกัน
    • ข้อเสียของฟีเจอร์ที่เน้นความสะดวก (สไตล์ Rust) คือมันซ่อน flow การแตกแขนงไว้ในบรรทัดเดียว ตั้ง breakpoint ตอนดีบักก็ยาก และให้น้ำหนักกับการ bubble ขึ้นไปอย่างสุดโต่งมากกว่าการ enrich/handling จึงเป็นรูปแบบไวยากรณ์ที่ Go เลือกไม่รับมาใช้ (เช่น ternary operator)
    • ต่อให้เทียบกับสไตล์ Rust ตรง ๆ ก็ยังมีคำถามเชิงเทคนิคว่าใน Go แล้วอะไรคือสิ่งที่เทียบเท่ากันได้แน่ชัด
    • หลังมี generics แล้ว ที่ว่าทำอะไรแบบสไตล์ Rust ได้ หมายถึงทำอะไรอย่างไร อยากเห็นตัวอย่างโค้ด
  • ผมคิดว่าภาษาไม่ควรถูกถกกันแบบติ๊กเช็กบ็อกซ์รับฟีเจอร์เหมือน Rust แต่ควรถูกออกแบบภายใต้ความสอดคล้องของภาพรวม การติ๊กครบทุกฟีเจอร์ไม่ได้แปลว่าควรเอาเข้ามาทันที เพราะมันอาจไม่เข้ากับแก่นแท้ของภาษานั้นจริง ๆ

    • Rust พอเดินไปในแนว design by committee ก็ทำให้เกิดภาพลักษณ์ว่าไวยากรณ์อ่านยากและขาดความสม่ำเสมอ
    • มีความเห็นว่าไม่มีอะไรอย่าง “ทางออกที่สมบูรณ์แบบ”
    • ผลสำรวจเองก็ไม่ได้ชี้ว่าการจัดการ error เป็นปัญหาร้ายแรงอันดับหนึ่งของ Go เพราะมีเพียง 13% ที่ตอบเช่นนั้น และก็มีผู้ใช้จำนวนไม่น้อยที่ชอบสภาพปัจจุบันอยู่แล้ว ดูผลสำรวจ