/ 365วันแห่งโปรแกรม

[365 วันแห่งโปรแกรม #day40] Generic Programming (ตอนที่ 3)

วันที่สี่สิบของ ‪#‎365วันแห่งโปรแกรม วันนี้ขอนำเสนอเรื่อง Generic Programming ตอนที่ 3


เมื่อวานเราดูวิธีสร้าง Generic Class และ Generic Method กันไปแล้ว ในวันนี้เราจะมาทำการทดลองกัน ผมไม่เจอคำถามเด็ดๆ เกี่ยวกับ Generic Class มา และคำถามนั้นก็คือ

ถ้า Generic Class ของเรานั้น มี static member แล้ว member ตัวนั้นจะเป็นตัวเดียวกันตลอดหรือไม่ หากเรา access จาก Generic Class โดยใส่ type parameter ต่างกัน

มีความเป็นไปได้อยู่สองสามอย่างที่อาจจะเกิดขึ้น ดังนี้

  1. เมื่อ member อยู่ในโหมด static แล้ว ไม่ว่าจะ access จาก type ใดๆ ของคลาสนั้น ย่อมได้ member ตัวเดิมกลับไป

  2. เมื่อเราอ้างถึง Generic Class ที่มี type parameter ต่างกัน ย่อมถือว่าเป็นคนละคลาสกัน ดังนั้น static member ที่ได้ย่อมเป็นคนละตัวกัน

  3. คุณสมบัติของ static member สิ้นสุดลงทันที เมื่ออยู่ใน Generic Class

งั้นเดี๋ยวเราจะเริ่มทดลองกนเลยครับ

วิธีการของเราในวันนี้คือสร้าง Generic Class ขึ้นมาคลาสนึง แล้วใส่ static member ไว้ หลังจากนั้นให้ลองพิมพ์ค่าของ static member เมื่อใส่ type parameter เป็น int และ string ลองเปลี่ยนค่าเป็นอย่างอื่น แล้วพิมพ์อีกครั้ง

เริ่มด้วยโค้ดในภาษา C# กันก่อนครับ

class Foo<T>
{
    public static int Bar;
}

...
Console.WriteLine("{0} {1}", Foo<int>.Bar, Foo<string>.Bar);
Foo<int>.Bar = 10;
Foo<string>.Bar = 20;
Console.WriteLine("{0} {1}", Foo<int>.Bar, Foo<string>.Bar);
...

===output===
0 0
10 20

จากผลลัพธ์เราพบว่าสมมติฐานข้อที่ 2 นั้นเป็นจริงครับ แต่เดี๋ยวก่อนครับมันอาจจะเป็นจริงแค่ใน C# ก็ได้ ดังนั้นเรามาลองใน C++ กันต่อเลยดีกว่า

using namespace std;

template <class T> class Foo {
public:
    volatile static int bar;
};

volatile int Foo<int>::bar = 0;
volatile int Foo<string>::bar = 0;

int main()
{
    cout << Foo<int>::bar << " " << Foo<string>::bar << endl;
    Foo<int>::bar = 10;
    Foo<string>::bar = 20;
    cout << Foo<int>::bar << " " << Foo<string>::bar << endl;
    return 0;
}

===output===
0 0
10 20

พบว่าได้ผลเหมือนกับใน C++ เลยครับ แต่เราจะยังลองอีกทีใน Java ครับ

class Foo<T>{
    public static int bar;
}

public class Main {
    public static void main(String[] args) {
        Foo<Integer> intFoo1 = new Foo<Integer>();
        Foo<String> stringFoo1 = new Foo<String>();
        Foo<Integer> intFoo2 = new Foo<Integer>();
        Foo<String> stringFoo2 = new Foo<String>();
    
        System.out.printf("%d %d %d %d\n", intFoo1.bar, intFoo2.bar, stringFoo1.bar, stringFoo2.bar);
    
        intFoo1.bar = 10;
        stringFoo1.bar = 20;
    
        System.out.printf("%d %d %d %d\n", intFoo1.bar, intFoo2.bar, stringFoo1.bar, stringFoo2.bar);
    }
}

===output===
0 0 0 0
20 20 20 20

ในจาวานั้นพบว่า เราไม่สามารถเข้าถึง static member ของ Generic Class แบบใส่ type parameter ได้ (ถ้าไม่ใส่ type parameter ทำได้) ดังนั้นผมจึงสร้าง instance ขึ้นมาแล้วทดลองด้วยวิธีเดิม ก็พบว่าในจาวาถือว่า static member ของ Generic Class จะเป็นตัวเดียวกันตลอดไม่ว่าจะ access จาก instance ที่สร้างโดยใส่ type parameter ไหนๆ และจาวาเองแนะนำให้เลี่ยงการ access static member จาก instance แล้วไป access จาก Type นั้นๆ โดยตรงอีกด้วย

ผลสรุปของเราในวันนี้คือ Generic Class นั้นอาจจะมีคุณสมบัติบางประการที่แตกต่างกันไปในแต่ละภาษา แต่คุณสมบติหลักคือการกำหนด type ทีหลังนั้นเหมือนกัน

วันนี้มี keyword เพิ่มขึ้นมาคำนึง นั่นคือ volatile แต่เราจะยังไม่พูดถึงในเร็วๆ นี้

#‎day40 #365วันแห่งโปรแกรม ‪#‎โครงการ365วันแห่ง‬...