Difference between a Value Type and a Reference Type

ตอนที่เริ่มเขียนโปรแกรม หลายคนคงคุ้นเคยกับคำว่า Value Type และ Reference Type ถ้าให้ผมอธิบายคราวๆ เจ้า value type เนี่ยมันจะเก็บ data ไว้ในหน่วยความจำส่วนของ stack memory ส่วน reference type มันจะสร้าง reference variable ไว้ใน stack memory และใช้ variable ที่เราประกาศ pointer ไปยัง data ซึ่งจะอยู่ในหน่วยความจำส่วนของ heap memory อีกที…ถ้าผมอธิบายแค่นี้มันอาจจะดูน้อยไป ฉะนั้นเรามาลุยกันต่อดีกว่าครับ

In Swift
Value Type — Structures
, Enums and tuples
Reference Type — Classes, Objects, Interfaces etc.
Java Programming Language

Value Type :

Value Type จะจัดสรรพื้นที่ของมันอยู่ภายใน stack memory ซึ่งตอนที่เราสร้างตัวแปรที่เป็น Value Type มันจะทำการสร้างพื้นที่หนึ่งพื้นที่เพื่อเก็บค่าไว้ใน memory (พูดง่ายๆคือมันจะสร้างกล่องและเก็บค่าที่เรา assign ให้มันไว้ภายในกล่องที่มันสร้างขึ้น) ส่วนกรณีที่เรา assign ตัวแปรเราให้กับตัวแปรอื่น มันคือการ copy ค่าให้กับตัวแปรอื่น ซึ่งหมายความว่าค่าในตัวแปรทั้งสองตัวนั้นเป็นคนละตัวกัน

int a;   // ประกาศตัวแปร a เป็น variable ซึ่งจะถูกสร้างใน stack memory
a = 80; // assign ค่าให้ตัวแปร a มีค่าเป็น 80
b = a; // copy ค่าที่อยู่ในตัวแปร a ให้กับตัวแปร b
เพิ่มเติม: ตอนที่ b = a; จะสั่งเกตุเห็นว่าตัวแปร a กับ b มีค่าเท่ากันคือ 80 แต่มันอยู่คนละ address กันใน stack memory ฉะนั้น…มันก็คือคนละตัว(another variable)กันนั่นเอง
Java Programming Language

Reference Type :

Reference Type จะเป็นการใช้ตัวแปร reference เพื่อจะใช้เป็นตัวอ้างอิงไปยัง object ที่ถูกสร้างไว้ใน heap memory (ตัวมันเองไม่ใช่ object เป็นแค่ reference variable เท่านั้น) ส่วนการ assign ค่าให้กับตัวแปรอื่นๆ มันไม่ใช่การ copy object ที่อยู่ใน heap เหมือนกับ value type แต่จะเป็นการบอกว่าจะต้องอ้างอิงไปหา object ตัวไหนใน heap …. ถ้านึกไม่ภาพไม่ออกก็ลองดูภาพด้านบน

Employee a = new Employee(); //ประกาศตัวแปร a เป็น instance pointer ของ Class Employee
a.age = 26; //assign ค่าใส่ในกล่องที่ตัวแปร a อ้างอิงถึงอยู่
Employee b = a; //ประกาศตัวแปร b เป็น instance pointer ซึ่งอ้างอิงไปยัง object เดียวกันกับตัวแปร a
b.age = 30; //assign ค่าใส่ในกล่องที่ตัวแปร b อ้างอิงถึงอยู่ ฉะนั้น a.age จะมีค่าเท่ากับ 30 เช่นเดียวกัน

เพิ่มเติม: ตอนที่ Employee b = a; จะสั่งเกตุเห็นว่าตัวแปร a กับ b อ้างอิงไปยัง object ที่สร้างใน heap memory ที่เดียวกัน ส่วนตัวแปล a กับ b จะถูกสร้างเป็น Reference Variable ใน stack memory ซึ่งอยู่คนละที่กัน
Java Programming Language — จากที่ผมได้กล่าวมาทั้งหมด ดูรูปนี้อีกทีจะเข้าใจมากขึ้น :)

— — -

เรื่องนี้ยังไม่จบนะครับ ใครที่เคยเขียนภาษา C++ จะต้องคุ้นเคยกับ operator เหล่านี้แน่นอน * และ & ใครไม่รู้จักผมขอพูดสั้นๆว่ามันเกี่ยวกับ pointer และ address

แล้วมันเกี่ยวอะไรกับ Value Type และ Reference Type ?

เกี่ยวกันตรงที่ว่า…ถ้าผมบอกว่า Class มันเป็น Reference Type ใช่ไหมครับ? ซึ่ง Reference Type จะสร้างตัวแปร pointer ไว้ใน stack memory แล้วอ้างอิงไปยัง obejct ใน heap memory ใช่ไหมครับ? 
แล้วถ้าผมทำแบบนี้ในภาษา C++ ละ….

C++ Programming Language

จากรูปมันจะพังทลายความคิดที่ว่า Class จะสร้าง object ไว้ใน heap memory ทันที เพราะ code ที่เราเห็น มันคือการสร้าง object ไว้ใน stack memory นั่นก็หมายความว่าการประกาศแบบนี้ก็คือ Value Type นั่นเอง

// ประกาศตัวแปร com1 เป็น variable ซึ่งจะถูกสร้างใน stack memory
Computer com1 = Computer();
// assign ค่าให้ตัวแปร model มีค่าเป็น “Macbook Pro”
com1.model = “Macbook Pro”;

// copy ค่าที่อยู่ในตัวแปร com1 ให้กับตัวแปร com2 ฉะนั้น com2.model จะมีค่าเริ่มต้นเป็น “Macbook Pro” เช่นกัน แต่เป็นคนละตัวกับ com1 เพราะถูก copy มา
Computer com2 = com1;
// assign ค่าให้ตัวแปร model ที่อยู่ใน com2 เป็น “Macbook Air” ซึ่งจะไม่มีผลอะไรกับ com1
com2.model = “Macbook Air”;

เราจะทำอย่างไรให้ภาษา C++ สามารถประกาศเป็นแบบ Reference Type ได้ละ?

คำตอบก็คือ operator * ที่หลายๆคนเรียกว่า “ดอกจัน” หรือ “ดัชนี” แต่คนคอมเรียกมันว่า pointer นั่นเอง(ขอโทษที่ทำให้เรื่องมันยาว =..=) ก็เจ้า pointer เนี่ยละครับ ที่จำทำให้ Class ของเราสามารถประกาศแบบ Reference Type ได้ ดูตามรูปข้างล่างเลยครับ

C++ Programming Language

จากรูปถ้าอ่านสิ่งที่กล่าวมาทั้งหมดตั้งแต่ต้นก็จะเข้าใจไม่ได้ไม่ยาก งั้นผมจะขออธิบาย code แต่ละบรรทัดเลยแล้วกันนะครับ

// ประกาศตัวแปร com1 เป็น instance pointer ของ Class Computer
Computer *com1 = Computer();
// assign ค่า “Macbook Pro” ให้ตัวแปร model ที่ com1 อ้างอิงถึงอยู่
com1.model = “Macbook Pro”;

// ประกาศตัวแปร com2 เป็น instance pointer ซึ่งอ้างอิง object เดียวกันกับ com1
Computer *com2 = com1;
// assign ค่าให้ตัวแปร model ที่อยู่ใน com2 เป็น “Macbook Air” ซึ่งจะทำให้ com1.model มีค่าเท่ากับ com2.model เพราะคือตัวเดียวกัน
com2.model = “Macbook Air”;

แล้วที่กล่าวมาในตอนแรกทั้งหมดมันคืออะไรวะเนี่ย??

ใจเย็นนะครับ คือผมกำลังจะอธิบายว่าในภาษาบางภาษาเช่น Java จะโดนบังคับด้วยภาษาให้ประกาศเป็น instance pointer โดยไม่ต้องมี operator * แบบภาษา C++ ฉะนั้นในภาษา Java จะไม่มีการประกาศเป็น instance variableใครที่เคยเขียน iOS ด้วยภาษา Swift ก็เช่นกัน….ฉะนั้นผมขอสรุปสั้นๆเลยว่า Value Type และ Reference Type มันเป็นแค่ concept ของการทำงานซึ่งจะทำงานอย่างไรนั้นขึ้นอยู่กับภาษาที่เลือกใช้ และวิธีการเขียนของแต่ละบุคคลครับ

You can download the ExampleValueTypeAndReferenceType here.