Static Type vs Dynamic Type: ไม่มีใครผิด แต่ก็ไม่มีใครถูก


เมื่อพูดถึง type system ในภาษา program เรามักจะพบว่ามีสองกลุ่มใหญ่ ๆ คือกลุ่มที่เชื่อใน static typing และอีกกลุ่มที่เชื่อใน dynamic typing — และต่างฝ่ายต่างก็มีเหตุผลของตัวเอง

Static Typers

คนที่อยู่สาย static typing จะให้ความสำคัญกับการให้ compiler ตรวจสอบทุกอย่างให้เรียบร้อยก่อน program จะถูก run จริง ๆ ซึ่งก็ดูสมเหตุสมผล — เพราะไม่มีใครอยากส่ง double เข้าไปใน function ที่รอรับ int

แต่พอใช้งานไปจริง ๆ เราจะเริ่มสร้าง custom types ของตัวเอง เช่น Employee, Order หรือ type ที่อิงกับ domain ต่าง ๆ และเราก็อยากรวม type พวกนี้ไว้ใน list

เพื่อจะทำแบบนั้น เราต้องใช้ generics หรือ template language ซึ่งในช่วงแรกก็ไม่มีปัญหาอะไร จนกระทั่งเราเริ่มเจอเรื่องอย่าง contravariance, covariance และ symbol แปลก ๆ เต็มไปหมดใน template syntax

สุดท้ายแล้ว code ก็จะซับซ้อนขึ้นเรื่อย ๆ จน type system กลายเป็น Turing-complete — ถึงขั้นที่สามารถเขียนโปรแกรมทั้งชุดให้ทำงานอยู่ใน compiler ได้เลย โดยไม่ต้อง run จริงแม้แต่บรรทัดเดียว!

และสิ่งที่น่าคิดก็คือ… language ที่ซับซ้อนขนาดนั้น กลับกลายเป็น dynamically typed ไปโดยไม่ทันรู้ตัว

มันเหมือนงูที่กินหางตัวเอง (Worm Ouroboros) ความคิดที่ต้องการความเป๊ะทุกระดับกลับกลายเป็นวนลูปกลับมาขัดแย้งในตัวเอง

Dynamic Typers

ทางฝั่ง dynamic typing จะมาพร้อมความรู้สึกปลดปล่อย — “เราไม่ต้องการ type! เดี๋ยว runtime จัดการให้เอง!” — ไม่ต้องกำหนดอะไรล่วงหน้าให้เยอะ เพราะ runtime จะจัดการเอง และ program ก็จะทำงานได้สวยงามเสมอ

โลกของ dynamic typing ดูเหมือนมีอิสระ เหมาะสำหรับการทดลองและพัฒนาอย่างรวดเร็ว แต่นั่นก็แลกมาด้วยความเสี่ยง เช่น bug ที่โผล่มาในเวลาที่ไม่คาดคิด

เรื่องจริงจากอดีต

ย้อนกลับไปหลายปีก่อน มีคนชื่อ Capers Jones ทำการศึกษาประสิทธิภาพของภาษา program ต่าง ๆ เขาพบว่า programmer ที่ใช้ Smalltalk มี productivity สูงกว่าคนที่ใช้ C++ ถึง 5 เท่า

Smalltalk เป็นภาษาที่ถูกออกแบบมาเพื่อรองรับแนวคิด object-oriented programming อย่างแท้จริง — ทุกอย่างคือ object แม้กระทั่งตัวเลขหรือ control structure เอง และยังมีลักษณะเป็น dynamically typed จึงให้ความรู้สึกคล่องตัวและยืดหยุ่นสูงในการพัฒนา

แน่นอน Smalltalk เป็น dynamically typed language ส่วน C++ เป็น statically typed และนั่นนำไปสู่สงครามระหว่าง Sun กับ IBM เพื่อแย่งชิงการเป็นภาษาแห่งอินเทอร์เน็ต

  • Sun ผลักดัน Java ซึ่งเป็นเหมือน C++ ที่ตัดบางอย่างออก
  • IBM ผลักดัน Smalltalk แต่ไม่เวิร์ก

สุดท้าย Java ชนะ และกลายเป็นมาตรฐานทั่วโลก แม้จะมีการสลับขั้วกลับไปกลับมาอยู่หลายรอบก็ตาม

สุดท้าย…ก็เปลี่ยนใจ

หลายคนเริ่มต้นด้วย static typing แล้วหมดไฟ เปลี่ยนไปใช้ Ruby ที่เป็น dynamic แต่ใช้ไปนาน ๆ ก็เบื่อ error ที่ไม่รู้จะโผล่มาเมื่อไหร่ เลยย้ายกลับไปหา Swift หรือภาษา static อื่น ๆ

วนไปวนมา…วนไปวนมา…

แล้วคำตอบคืออะไร?

บางคนบอกว่า “dynamic ดีกว่า” — แต่จริง ๆ แล้วก็ไม่เหมาะกับระบบวิกฤต เช่น missile system ที่ถ้าเกิด type error ตอนก่อนระเบิด 5 milliseconds คงไม่ใช่เรื่องตลก

ในขณะเดียวกัน “static ก็ไม่เวิร์ก” — เพราะมันซับซ้อนจนกลายเป็น dynamic ไปเอง

แล้วคำตอบที่แท้จริงคืออะไร?

คำตอบคือ…

✅ ตรวจสอบ type ของคุณตอน test time

ไม่ต้องถึงขั้น runtime ไม่ต้องถึงขั้น compile-time แค่เขียน test ที่ดี และปล่อยให้มันช่วยตรวจความถูกต้องของ type — แค่นั้นก็พอแล้ว

References: