1 คะแนน โดย GN⁺ 2024-08-09 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

สรุป

เอกสารนี้เป็นข้อเสนอเกี่ยวกับ type unions (หรือ discriminated unions) ใน C#

แรงจูงใจ

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

แนวทางแก้ไข

  • วิธีที่เหมาะสมที่สุดในการทำให้ union types ใช้งานได้ใน C# อาจมองได้ว่าเป็นโครงสร้างลำดับชั้นที่ใช้ abstract base class
  • อย่างไรก็ตาม ยังมีปัญหาเช่นข้อจำกัดของโครงสร้างลำดับชั้น และการไม่สามารถแสดงยูเนียนของชนิดที่ไม่เกี่ยวข้องกันได้
  • อาจต้องการยูเนียนหลายรูปแบบ และข้อเสนอนี้แบ่งออกเป็น 4 หมวดหมู่

มาตรฐาน - union class

การประกาศ

  • union class ถูกประกาศในลักษณะคล้าย enum
  • แต่ละสมาชิกสามารถมี state variables ได้

การสร้าง

  • สร้างโดยกำหนดอินสแตนซ์ของชนิดสมาชิก

การแยกโครงสร้าง

  • แยกโครงสร้างด้วย type tests และ pattern matching

ความครอบคลุม

  • หากพิจารณาชนิดสมาชิกทั้งหมดใน switch expression หรือ statement ก็ไม่จำเป็นต้องมีเคสเริ่มต้น

Nullability

  • สามารถรวม null ได้โดยใช้สัญกรณ์ nullability มาตรฐาน

การใช้งานจริง

  • union class ถูก implement เป็น abstract record class

แบบเฉพาะทาง - union struct

การประกาศ

  • ประกาศคล้าย union class แต่เพิ่มคีย์เวิร์ด struct

การสร้าง

  • สร้างโดยกำหนดอินสแตนซ์ของชนิดสมาชิก

การแยกโครงสร้าง

  • แยกโครงสร้างด้วย type tests และ pattern matching

ความครอบคลุม

  • หากพิจารณาชนิดสมาชิกทั้งหมดใน switch expression หรือ statement ก็ไม่จำเป็นต้องมีเคสเริ่มต้น

Nullability

  • สามารถรวม null ได้โดยใช้สัญกรณ์ nullability มาตรฐาน

ค่าเริ่มต้น

  • union struct อาจอยู่ในสถานะที่ไม่ได้กำหนดเมื่อยังไม่ถูกกำหนดค่า หรือถูกกำหนดเป็นค่าเริ่มต้น

การใช้งานจริง

  • union struct ถูก implement เป็น struct และชนิดสมาชิกถูก implement เป็น nested record struct

แบบชั่วคราว - ad hoc union

ไวยากรณ์

  • ad hoc union ถูกอ้างอิงโดยใช้ไวยากรณ์แพตเทิร์น or

การตั้งชื่อ

  • สามารถตั้งชื่อร่วมให้กับ ad hoc union ได้ด้วย file หรือ global using alias

การสร้าง

  • สร้างโดยกำหนดอินสแตนซ์ของชนิดสมาชิก

การแยกโครงสร้าง

  • แยกโครงสร้างด้วย type tests และ pattern matching

ความครอบคลุม

  • หากพิจารณาชนิดสมาชิกทั้งหมดใน switch expression หรือ statement ก็ไม่จำเป็นต้องมีเคสเริ่มต้น

Nullability

  • สามารถรวม null ได้โดยใช้สัญกรณ์ nullability มาตรฐาน

การใช้แทนกันได้

  • ad hoc union ที่มีชนิดสมาชิกเหมือนกันสามารถใช้แทนกันได้

user-defined unions

  • สามารถประกาศ union type ที่ไม่สามารถระบุเป็น union class หรือ union struct ได้
  • สามารถปิดโครงสร้างลำดับชั้นได้ด้วยแอตทริบิวต์ Closed
  • สามารถ implement เป็น struct wrapper ได้ด้วยแอตทริบิวต์ Union

common unions

Option

  • เป็น struct union ที่แทนค่าที่อาจมีอยู่หรือไม่มีอยู่ก็ได้

Result

  • เป็น struct union สำหรับคืนผลลัพธ์ที่สำเร็จหรือข้อผิดพลาดจากฟังก์ชัน

ข้อเสนอที่เกี่ยวข้อง

โครงสร้างลำดับชั้นแบบปิด

  • ประกาศชุดของ subtype แบบปิดสำหรับ abstract base type โดยใช้แอตทริบิวต์ Closed

ค่า singleton

  • ชนิดที่มีแอตทริบิวต์ singleton สามารถใช้เป็นค่าได้ในบริบทที่ไม่ใช่ชนิด

การย่อสมาชิกที่ซ้อนกัน

  • สามารถ bind ไปยัง static member หรือ nested type ของ target type ได้โดยใช้ชื่อที่ไม่ bind ไว้ล่วงหน้า

สรุปโดย GN⁺

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

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

 
GN⁺ 2024-08-09
ความคิดเห็นจาก Hacker News
  • เคยใช้ discriminated unions ใน F# มาก่อน และคิดว่าน่าจะมีใน C# ด้วย

    • ตอนนี้ใช้ Java อยู่ และรู้สึกว่าการต้องกลับไปใช้ภาษาที่ไม่มี ADT นั้นยาก
    • ดีใจที่ไม่ต้องคอยแก้ตัวให้กับการขาดฟีเจอร์สำคัญของ C# อีกต่อไป
  • คำว่า "type unions" ฟังดูไม่คุ้นเคย

    • ดูคล้ายกับ tagged unions ในภาษาตระกูล ML
    • สงสัยว่านักพัฒนา C# มีแนวโน้มจะตั้งชื่อที่ต่างจากคำศัพท์เดิมหรือไม่
  • ในฐานะนักพัฒนา C# มานาน รู้สึกว่ายังไม่เห็น use case ของข้อเสนอนี้ชัดเจน

    • ดูเหมือนว่าจะทำได้ด้วยการประกาศ empty interface และ record classes
    • สงสัยว่ามีอะไรที่ตัวเองกำลังมองข้ามไปหรือไม่
  • TypeScript มี type unions อยู่แล้ว

    • ดูคล้ายกับ discriminated unions ของ F# หรือ Haskell
    • discriminated unions มี named case constructors
  • หากไม่มียูเนียนที่ทำ pattern matching ได้ การเขียนโปรแกรมจะยากขึ้น

    • ยังไม่ได้เข้าใจความหมายของ expression problem อย่างถ่องแท้
    • จุดขยายผ่าน polymorphism แบบเดิมอาจเหมาะกับผู้ใช้ไคลเอนต์ในอนาคต
    • แต่สำหรับโค้ดที่ทีมเป็นเจ้าของเอง ยูเนียนที่ทำ pattern matching ได้อาจเหมาะกว่า
  • เคยมีประสบการณ์ใช้ field offsets ใน C# unions

    • การ alias ระหว่าง pointer/reference values กับ values อาจทำให้เกิด undefined behavior ได้
    • struct union ของ u64 กับ object อาจต้องมีฟิลด์แยก ทำให้สิ้นเปลืองไป 8 ไบต์
  • ใช้ private constructors และแพ็กเกจ nuget เพื่อให้ switch types ไม่ต้องมีเคส _

    • คล้ายกับเวอร์ชันที่ desugar แล้วของ "union classes" ที่เสนอมา
    • เป็นเรื่องดีที่ไม่ต้องพึ่งแพ็กเกจ nuget และได้ syntax sugar เพิ่มเข้ามา
  • ไม่มีการกล่าวถึงว่า union structs จะจัดการกับ tearing อย่างไรเมื่อมีการแก้ไขพร้อมกัน

    • tearing อาจก่อให้เกิดปัญหาด้าน memory safety ได้
    • อาจมี variant ที่มีทั้งฟิลด์จำนวนเต็มและฟิลด์อ้างอิงอยู่ที่ offset เดียวกัน