Genericity

    ทั้ง C# รุ่นใหม่ 8.0 และ Java 5.0 ต่างก็เห็นชอบกันว่า ต้องเอาเรื่อง Genericity มาใส่ไว้ในภาษา ผมเลยอยากจะแนะนำให้รู้จักกันไว้ก่อน ถึงแม้ว่าจะดูเร็วเกินไปสำหรับ C# เพราะยังอยู่ในขั้น Beta ยังมีอะไรเปลี่ยนแปลงได้อีกมาก แต่ความสามารถนี้เป็นความสามารถหลักของตัวภาษาที่ต่างฝ่าย ต่างชูขึ้นมาเป็นประเด็นหลัก ดังนั้นแนวโน้ม คงเป็นที่นิยมแน่ รู้ก่อนย่อมได้เปรียบ

เริ่มกันที่ C++

    ถ้าจำไม่ผิด แนวคิดของ Genericity ผมเคยได้รับรู้เป็นครั้งแรก เมื่อสิบกว่าปีที่แล้วในหนังสือที่รู้จักกันภายใต้ชื่อย่อว่า ARM หรือ The Annotated C++ Reference Manual ผมขอจากให้เพื่อนที่อเมริกา ซื้อแล้วส่งมาให้ สมัยนั้นยังไม่มี Amazon ยังไม่มี Web ข้อมูลของการเขียนโปรแกรมทั้งหลาย ผมได้จากวรสาร Dr. Dobb Journal  พอได้หนังสือมาดีใจมากครับ เป็นปกแข็งสวยเชียว สมัยก่อนหายากมากครับหนังสือคอมปกแข็ง มีแต่ปกสีเขียว สีแดงเป็น Version ขายถูก วันนี้กลับไปดูหนังสือเล่มนี้อีก ความรู้สึกเก่าๆ มันก็กลับมาครับ มีความสุขครับ

     หนังสือเล่มนี้ Stroustrup ผู้คิดค้นภาษา C++ เป็นผู้เขียนท่านหนึ่งในนั้น เขาไม่ได้ใช้คำว่า Genericity แต่หากใช้คำว่า Template ซึ่งเราจะมาดูรายละเอียดกันต่อไป ส่วนคำว่า Genericity จริงๆ ผมเรียนรู้มาจากหนังสือ Object-Oriented Software Construction ของ Bertrand Meyer ในบทความเก่าๆ ผมเคยแนะนำหนังสือเล่มนี้ไปแล้ว นั่นทำให้ผมเห็นถึงความสวยงามของภาษา Eiffel มาวันนี้ C# และ Java จะเอา Genericity มาใช้ ผมขอนำเสนอแนวคิดของ Genericity ผ่านภาษา C++ ก็แล้วกัน เพราะเราคุ้นเคยกับ Syntax ของภาษาตระกูล C มากกว่า Eiffel

    เพื่อให้เข้าใจเรื่องราวของ Genericity เรามาลองดูตัวอย่างนี้กันครับ

class Sum
{
private:
   int _count;
   int _arr[100];
public:
   Sum() { _count = 0; }
   void add(int num)
   {
      arr[_count++] = num;
   }

   int getResult()
   {
      int total = 0;
      for (int i=0; i < _count; i++) {
         total += _arr[i];
      }
      return total;
   }
};

    class นี้เป็น class ง่ายๆ ภาษา C++ คิดว่าคงอ่านกันรู้เรื่อง มันมีรูรั่วอยู่พอสมควร เรามองข้ามมันไปครับ สมมุติว่ามันทำงานได้ดี มันคงไม่มีอะไร ถ้าเกิดอีกวันเราต้องการใส่ค่าเป็นทศนิยม แน่นอนครับ class นี้ไม่รองรับ สิ่งที่เรามักจะทำกันก็คือ copy class นี้ไปแล้วตั้งชื่อใหม่ สมมุติว่าเป็น SumDouble จากนั้นก็ไล่แก้ int ที่ใช้ในการเก็บข้อมูลให้กลายเป็น Double ให้หมด ไม่รู้คุณเคยนึกเหมือนผมไหม มันน่าจะมีวิธีใช้ Code ร่วมกันได้ ก็เมือนกันหมดทุกส่วน ต่างแต่ชนิดตัวแปรเท่านั้น มีครับในภาษา C++ เขามี template ให้ใช้ เรามาลองดู Code แบบเดียวกันกับข้างบน แต่ใช้ Template ดูครับ

template <typename X>
class Sum
{
private:
   int _count;
   X _arr[100];
public:
   Sum() { _count = 0; }
   void add(X num)
   {
      arr[_count++] = num;
   }

   X getResult()
   {
      X total = 0;
      for (int i=0; i < _count; i++) {
         total += _arr[i];
      }
      return total;
   }
};

     การเขียนลักษณะนี้ เหมือนกันการทำ Template เลยครับ เช่น เราอาจจะมี Template ของคำสั่ง for  ผมก็เก็บเป็น for (int i=0; i<number; i++) { }  จากนั้นคุณก็ Map เข้ากับ keyboard เช่น CTRL-F เมื่อคุณกด CTRL-F มันจะแสดงบันทัดข้างต้นขึ้นมา คุณก็เพียงเปลี่ยนตัวแปร number ให้เป็นตัวแปรที่คุณต้องการ เท่านั้นก็ประหยัดแรงงานได้เยอะครับ Editor ดีๆ หลายตัวทำแบบนี้ได้ Code ข้างต้นก็คล้ายๆ กับ Template อยู่เหมือนกัน เวลาใช้งาน ผมเขียนอย่างนี้ครับ

Sum<int> s;

    แทนที่แบบเดิมเวลาคุณสร้างตัวแปรคุณใช้ Sum s;  เราก็เพิ่ม Parameter เข้าไปว่าเป็น int (ตามตัวอย่างข้างต้น) จากนั้น C++ ก็ไปไล่แทน X ให้กลายเป็น int หมด เวลาที่คุณกด Intellisense คุณจะเห็น method add() รับ Parameter เป็น int ไม่ใช่เป็น X ครับ

    ลึกๆ แล้ว C++ ทำอย่างไร C++ ใช้ Preprocessor ครับ ถ้าใครไม่รู้จักก็ไม่เป็นไร เอาเป็นว่า ถ้าคุณมี Sum<int> และ Sum<double> จริงๆ แล้ว C++ แอบสร้าง Class 2 Class ที่อิสระต่อกันครับ ซึ่งไม่เหมือนกัน C# ที่ผมจะกล่าวต่อไป ซึ่งมองรวมกันเป็น Class เดียว สำหรับเนื้อหาของ C++ ผมขอหยุดไว้เท่านี้ จริงๆ แล้ว template ของ C++ ยังมีลูกเล่นอีกมากเช่น การกำหนด template ระดับ method แทนที่ระดับ class อย่างตัวอย่างข้างต้น แต่มันชักจะไปกันใหญ่ ไม่เกี่ยวกับ C# ที่เรากำลังสนใจ เลยขอข้ามไปครับ

มาดู Genericity ใน C# กันดีกว่า

    โควต้าเวลาหมดครับ ต่อคราวหน้าก็แล้วกัน